Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Uncaught [TypeError: Cannot read property 'setAttribute' of undefined] #441

Open
dac514 opened this issue Jun 12, 2019 · 10 comments
Open

Uncaught [TypeError: Cannot read property 'setAttribute' of undefined] #441

dac514 opened this issue Jun 12, 2019 · 10 comments

Comments

@dac514
Copy link

dac514 commented Jun 12, 2019

I'm working on an express.js app that wraps this library and returns a PNG image. Sometimes the equations will be less than stellar, possibly garbage. This example crashes my node app, leaves it in an usable state, I have to restart the server:

Equation:

\begin{equation*} A = \left[ \begin{array}{cccc} a_{11} & a_{12} & a_{13} & a_{14} \\ a_{21} & a_{22} & a_{23} & a_{24} \\ a_{31} & a_{32} & a_{33} & a_{34} \end{array} \right] \end{equation*}

Error:

Math Processing Error: Cannot read property 'toFixed' of undefined                                                                                                      
Error: TypeError: Cannot read property 'setAttribute' of undefined                                                                                                      
    at GetSVG (C:\Users\dac\Code\github\pressbooks\pb-mathjax\node_modules\mathjax-node\lib\main.js:698:7)                                                              
    at Function.execute (file:///C:/Users/dac/Code/github/pressbooks/pb-mathjax/node_modules/mathjax/unpacked/MathJax.js:243:26)                                        
    at cb (file:///C:/Users/dac/Code/github/pressbooks/pb-mathjax/node_modules/mathjax/unpacked/MathJax.js:225:59)                                                      
    at Object.Process (file:///C:/Users/dac/Code/github/pressbooks/pb-mathjax/node_modules/mathjax/unpacked/MathJax.js:495:38)                                          
    at Object.call (file:///C:/Users/dac/Code/github/pressbooks/pb-mathjax/node_modules/mathjax/unpacked/MathJax.js:508:37)                                             
    at Function.WAITEXECUTE (file:///C:/Users/dac/Code/github/pressbooks/pb-mathjax/node_modules/mathjax/unpacked/MathJax.js:348:50)                                    
    at cb (file:///C:/Users/dac/Code/github/pressbooks/pb-mathjax/node_modules/mathjax/unpacked/MathJax.js:225:59)                                                      
    at Object.Process (file:///C:/Users/dac/Code/github/pressbooks/pb-mathjax/node_modules/mathjax/unpacked/MathJax.js:495:38)                                          
    at Object.call (file:///C:/Users/dac/Code/github/pressbooks/pb-mathjax/node_modules/mathjax/unpacked/MathJax.js:508:37)                                             
    at Function.WAITEXECUTE (file:///C:/Users/dac/Code/github/pressbooks/pb-mathjax/node_modules/mathjax/unpacked/MathJax.js:348:50)                                    
Error: Uncaught [TypeError: Cannot read property 'setAttribute' of undefined]                                                                                           
    at reportException (C:\Users\dac\Code\github\pressbooks\pb-mathjax\node_modules\jsdom\lib\jsdom\living\helpers\runtime-script-errors.js:66:24)                      
    at processJavaScript (C:\Users\dac\Code\github\pressbooks\pb-mathjax\node_modules\jsdom\lib\jsdom\living\nodes\HTMLScriptElement-impl.js:192:7)                     
    at HTMLScriptElementImpl._innerEval (C:\Users\dac\Code\github\pressbooks\pb-mathjax\node_modules\jsdom\lib\jsdom\living\nodes\HTMLScriptElement-impl.js:122:5)      
    at C:\Users\dac\Code\github\pressbooks\pb-mathjax\node_modules\jsdom\lib\jsdom\browser\resource-loader.js:31:22                                                     
    at Object.check (C:\Users\dac\Code\github\pressbooks\pb-mathjax\node_modules\jsdom\lib\jsdom\living\nodes\Document-impl.js:76:11)                                   
    at C:\Users\dac\Code\github\pressbooks\pb-mathjax\node_modules\jsdom\lib\jsdom\living\nodes\Document-impl.js:95:12                                                  
    at wrappedEnqueued (C:\Users\dac\Code\github\pressbooks\pb-mathjax\node_modules\jsdom\lib\jsdom\browser\resource-loader.js:253:16)                                  
    at ReadStream.readableStream.on (C:\Users\dac\Code\github\pressbooks\pb-mathjax\node_modules\jsdom\lib\jsdom\browser\resource-loader.js:74:7)                       
    at ReadStream.emit (events.js:203:15)                                                                                                                               
    at endReadableNT (_stream_readable.js:1129:12) TypeError: Cannot read property 'setAttribute' of undefined                                                          
    at GetSVG (C:\Users\dac\Code\github\pressbooks\pb-mathjax\node_modules\mathjax-node\lib\main.js:698:7)                                                              
    at Function.execute (file:///C:/Users/dac/Code/github/pressbooks/pb-mathjax/node_modules/mathjax/unpacked/MathJax.js:243:26)                                        
    at cb (file:///C:/Users/dac/Code/github/pressbooks/pb-mathjax/node_modules/mathjax/unpacked/MathJax.js:225:59)                                                      
    at Object.Process (file:///C:/Users/dac/Code/github/pressbooks/pb-mathjax/node_modules/mathjax/unpacked/MathJax.js:495:38)                                          
    at Object.call (file:///C:/Users/dac/Code/github/pressbooks/pb-mathjax/node_modules/mathjax/unpacked/MathJax.js:508:37)                                             
    at Function.WAITEXECUTE (file:///C:/Users/dac/Code/github/pressbooks/pb-mathjax/node_modules/mathjax/unpacked/MathJax.js:348:50)                                    
    at cb (file:///C:/Users/dac/Code/github/pressbooks/pb-mathjax/node_modules/mathjax/unpacked/MathJax.js:225:59)                                                      
    at Object.Process (file:///C:/Users/dac/Code/github/pressbooks/pb-mathjax/node_modules/mathjax/unpacked/MathJax.js:495:38)                                          
    at Object.call (file:///C:/Users/dac/Code/github/pressbooks/pb-mathjax/node_modules/mathjax/unpacked/MathJax.js:508:37)                                             
    at Function.WAITEXECUTE (file:///C:/Users/dac/Code/github/pressbooks/pb-mathjax/node_modules/mathjax/unpacked/MathJax.js:348:50)                                    

Configs:

{
      MathJax: {
        extensions: ['Safe.js'],
        displayMessages: false,
        displayErrors: false,
        AsciiMath: {
          // @see http://docs.mathjax.org/en/latest/asciimath.html
        },
        SVG: {
          blacker: 0,
        },
      },
    }
{
      math: myEquation,
      format: 'AsciiMath',
      svg: true,
      speakText: true, // a11y
    }

I've tried putting the code in a try/catch block but it doesn't do anything.

Help?

@dpvc
Copy link
Member

dpvc commented Jun 12, 2019

The main issue is that you have specified that your expression is an AsciiMath one, but really it is a TeX one. It appears that AsciiMath produces bad MathML when given this TeX expression.

If you change

format: 'AsciiMath'

to

format: 'TeX'

it should work for you.

An additional issue is that you have included displayMesages and displayErrors in the MathJax configuration block, but they should be outside that in the main configuration object:

    {
      displayMessages: false,
      displayErrors: false,
      MathJax: {
        extensions: ['Safe.js'],
        AsciiMath: {
          // @see http://docs.mathjax.org/en/latest/asciimath.html
        },
        SVG: {
          blacker: 0,
        },
      },
    }

But setting the wrong format is the one that is causing you the errors above.

@dac514
Copy link
Author

dac514 commented Jun 12, 2019

Thank you for your reply, but:

Sometimes the equations will be less than stellar, possibly garbage.

My main concern is that I need to be able to recover from this error.

Similar errors (bad MathML, bad TeX) throw errors I can catch.

This one puts me in a weird limbo state. My app crashes and I can't do anything. Express.js simply hangs forever. I cannot do try/catch, I cannot do then().catch() and I can't seem to do process.on('unhandledRejection') or process.on('uncaughtException')

Here's the app in question: https://github.com/pressbooks/pb-mathjax

Here's a URL that crashes it:

http://localhost:3000/asciimath?asciimath=%5Cbegin%7Bequation%2A%7D%20%20A%20%3D%20%5Cleft%5B%20%5Cbegin%7Barray%7D%7Bcccc%7D%20%20a_%7B11%7D%20%26%20a_%7B12%7D%20%26%20a_%7B13%7D%20%26%20a_%7B14%7D%20%5C%5C%20%20a_%7B21%7D%20%26%20a_%7B22%7D%20%26%20a_%7B23%7D%20%26%20a_%7B24%7D%20%5C%5C%20%20a_%7B31%7D%20%26%20a_%7B32%7D%20%26%20a_%7B33%7D%20%26%20a_%7B34%7D%20%20%5Cend%7Barray%7D%20%5Cright%5D%20%20%5Cend%7Bequation%2A%7D&fg=561442

If I pass the same "junk" to MathML:

http://localhost:3000/mathml?mathml=%5Cbegin%7Bequation%2A%7D%20%20A%20%3D%20%5Cleft%5B%20%5Cbegin%7Barray%7D%7Bcccc%7D%20%20a_%7B11%7D%20%26%20a_%7B12%7D%20%26%20a_%7B13%7D%20%26%20a_%7B14%7D%20%5C%5C%20%20a_%7B21%7D%20%26%20a_%7B22%7D%20%26%20a_%7B23%7D%20%26%20a_%7B24%7D%20%5C%5C%20%20a_%7B31%7D%20%26%20a_%7B32%7D%20%26%20a_%7B33%7D%20%26%20a_%7B34%7D%20%20%5Cend%7Barray%7D%20%5Cright%5D%20%20%5Cend%7Bequation%2A%7D&fg=561442

It complains just as much, but I can catch the error and do something about it.

Ideas?

dac514 added a commit to pressbooks/pb-mathjax that referenced this issue Jun 12, 2019
@pkra
Copy link
Contributor

pkra commented Jun 13, 2019

This is, ultimately, an upstream issue in MathJax and asciimath. There should be a better error handling on MathJax's end and, ultimately, asciimath should produce some reasonable output for this (bad) input.

However, since your project is in its early stages (great to see PB making this btw!), you might consider jumping ahead to MathJax v3.

@pkra
Copy link
Contributor

pkra commented Jun 13, 2019

I've filed asciimath/asciimathml#106 and mathjax/MathJax#2153 -- reduced test case: {cc}.

@dac514
Copy link
Author

dac514 commented Jun 13, 2019

However, since your project is in its early stages (great to see PB making this btw!), you might consider jumping ahead to MathJax v3.

Thanks for the reply and upstream reports!

I looked at mj3-demos-node and see: tex2svg and mml2svg examples in: https://github.com/mathjax/mj3-demos-node/tree/master/component but I don't see asciimath2svg. Docs and release notes for the latest beta say "Other input and output processors (e.g., AsciiMath input) will be added in the future." Is this still the case or is there some development branch I can point to? Supporting AsciiMath is a feature we'd like to promote when this is released.

For now, for this particular issue, I've set a timer that exits the script if (I think that) something crashed. Works like:

  // Consider an init longer than 5 seconds a crash and exit
  const tooLong = setTimeout(() => {
    // @see https://github.com/mathjax/MathJax-node/issues/441
    console.error('Too long, Something crashed? Please restart the server.');
    process.exit(1);
  }, 5000);
  mjAPI.config(configs.mathjax);
  mjAPI.typeset(configs.typeset).then((data) => {
    clearTimeout(tooLong);
	// ... snip ...
  }).catch((err) => {
    clearTimeout(tooLong);
	// ... snip ...
  });

Node severs like pm2 and forever will restart automatically when this happens, good enough for now.

@dpvc
Copy link
Member

dpvc commented Jun 13, 2019

Sometimes the equations will be less than stellar, possibly garbage.

Sorry, I thought you meant the resulting output was bad, not the input provided to MathJax. I understand what you re saying now.

My main concern is that I need to be able to recover from this error.

It turns out that mathjax-node doesn't handle the case where the SVG wasn't created (in this case, due to AsciiMath crashing on the bad input). Because MathJax is running inside a jsdom virtual DOM inside mathjax-node, your try/catch are unable to trap the error.

If you add

if (!svg) return;

in between lines 697 and 698

MathJax-node/lib/main.js

Lines 697 to 698 in c7e5bf3

svg = script.previousSibling.getElementsByTagName("svg")[0];
svg.setAttribute("xmlns","http://www.w3.org/2000/svg");

in node_modules/mathjax-node/lib/main.js, that will prevent this crash, and your mjAPI.typeset() call will pass on the error so that your catch will run with err being the array of errors that caused the problem. In this case, it will be a Math Processing Error since the AsciiMath input jax died.


... I don't see asciimath2svg ... is there some development branch I can point to?

The AsciiMath input jax has not yet been ported to v3, but there is a legacy v2 AsciiMath input jax that is patched in for testing purposes. To use it, you would need to use the "direct" method of loading MathJax, rather than the components (since no AsciiMath components are included), or you could build your own component for AsciiMath (starting with the MathML input component as a template, it should not be too hard). The legacy AsciiMath input jax is asynchronous, so you would have to use the promise-based conversion features; but you are already working with promises, so that should not be a problem.

It would take a little more work to get AsciiMath working in v3 than to make the one-line fix to mathjax-node that I give above, but I suspect it will be worth it, as it will be both faster, more stable, and more maintainable in the long run.

@dpvc
Copy link
Member

dpvc commented Jun 13, 2019

I was just trying out an AsciiMath component for MathJax v3, and realized that because of the legacy v2 code, you can't webpack it. If your app requires the code to be webpacked, then you won't be able to use AsciiMath until it is properly ported to v3.

@dpvc
Copy link
Member

dpvc commented Jun 13, 2019

OK, it is possible to make a webpackable asciimath component by changing

https://github.com/mathjax/mathjax-v3/blob/660ad53770f47915f6e99abf62299e7da343fa5e/mathjax2/legacy/MathJax.js#L776

to

timeout();

and

https://github.com/mathjax/mathjax-v3/blob/660ad53770f47915f6e99abf62299e7da343fa5e/mathjax2/input/AsciiMath.js#L1

to

MathJax = Object.assign(global.MathJax || {}, require("../legacy/MathJax.js").MathJax);

Then the component can be modeled on components/src/input/mathml and basically just change mml to asciimath and MathML to AsciiMath throughout. The entities subdirectory can be removed.

@dpvc
Copy link
Member

dpvc commented Jun 13, 2019

I've made a asciimath-component branch of the v3 code that includes the webpackable AsciiMath component.

@dac514
Copy link
Author

dac514 commented Jun 21, 2019

Update: I'm going to hold off on MathJax3. The syntax & convention changes from this project to that one aren't trivial for me. I spent an hour trying to wedge it into pb-mathjax and failed.

Would love #442 integrated though.

Regards,

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants