Skip to content

Speech generation error for empty mtr #3453

@TylerZeroMaster

Description

@TylerZeroMaster

Issue Summary

When math input for tex-mml-svg/MathJax.mathml2svgPromise contains at least one empty mtr and speech is enabled, a speech generation error is logged to the console (not thrown), and speechis not generated.

Steps to Reproduce:

  1. Follow steps to load tex-mml-svg component in node
  2. Call MathJax.mathml2svgPromise with sample math and display: false
  3. See error logged in console

Sample math that is affected by this issue:

  <m:math xmlns="http://www.w3.org/1999/xhtml" xmlns:m="http://www.w3.org/1998/Math/MathML" display="inline">
    <m:semantics>
      <m:mrow>
        <m:mrow data-sm="./modules/m82530/index.cnxml:873:42">
          <m:mspace width="4em" data-sm="./modules/m82530/index.cnxml:873:50" />
          <m:mtable data-sm="./modules/m82530/index.cnxml:873:73">
            <!-- Empty mtr -->
            <m:mtr data-sm="./modules/m82530/index.cnxml:873:83" />
            <m:mtr data-sm="./modules/m82530/index.cnxml:873:91">
              <m:mtd columnalign="right" data-sm="./modules/m82530/index.cnxml:873:98">
                <m:msup data-sm="./modules/m82530/index.cnxml:873:125">
                  <m:mi data-sm="./modules/m82530/index.cnxml:873:133">n</m:mi>
                  <m:mn data-sm="./modules/m82530/index.cnxml:873:147">2</m:mn>
                </m:msup>
                <m:mo data-sm="./modules/m82530/index.cnxml:873:170">+</m:mo>
                <m:mi data-sm="./modules/m82530/index.cnxml:873:184">n</m:mi>
              </m:mtd>
              <m:mtd columnalign="left" data-sm="./modules/m82530/index.cnxml:873:206">
                <m:mo data-sm="./modules/m82530/index.cnxml:873:232">=</m:mo>
              </m:mtd>
              <m:mtd columnalign="left" data-sm="./modules/m82530/index.cnxml:873:254">
                <m:mn data-sm="./modules/m82530/index.cnxml:873:280">132</m:mn>
              </m:mtd>
            </m:mtr>
          </m:mtable>
        </m:mrow>
      </m:mrow><m:annotation-xml encoding="MathML-Content">
        <m:mrow data-sm="./modules/m82530/index.cnxml:873:42">
          <m:mspace width="4em" data-sm="./modules/m82530/index.cnxml:873:50" />
          <m:mtable data-sm="./modules/m82530/index.cnxml:873:73">
            <m:mtr data-sm="./modules/m82530/index.cnxml:873:83" />
            <m:mtr data-sm="./modules/m82530/index.cnxml:873:91">
              <m:mtd columnalign="right" data-sm="./modules/m82530/index.cnxml:873:98">
                <m:msup data-sm="./modules/m82530/index.cnxml:873:125">
                  <m:mi data-sm="./modules/m82530/index.cnxml:873:133">n</m:mi>
                  <m:mn data-sm="./modules/m82530/index.cnxml:873:147">2</m:mn>
                </m:msup>
                <m:mo data-sm="./modules/m82530/index.cnxml:873:170">+</m:mo>
                <m:mi data-sm="./modules/m82530/index.cnxml:873:184">n</m:mi>
              </m:mtd>
              <m:mtd columnalign="left" data-sm="./modules/m82530/index.cnxml:873:206">
                <m:mo data-sm="./modules/m82530/index.cnxml:873:232">=</m:mo>
              </m:mtd>
              <m:mtd columnalign="left" data-sm="./modules/m82530/index.cnxml:873:254">
                <m:mn data-sm="./modules/m82530/index.cnxml:873:280">132</m:mn>
              </m:mtd>
            </m:mtr>
          </m:mtable>
        </m:mrow>
      </m:annotation-xml>
    </m:semantics>
  </m:math>
  • At first I thought this was more closely related to SRE, however, when I run SRE.toSpeech on the sample math, it works.
  • I believe this is a bug because removing the empty mtr element fixes the issue; however, empty mtr is valid MathML.
  • I would expect the speech to generate normally, as it does when the mtr elements have been removed, without any errors appearing in the console. ("1 lines Line 1: n squared plus n equals 132")

Technical details:

  • MathJax Version: 4.0.0
  • Client OS: Mac OS X 14.7.8
  • Browser: N/A (liteDOM adaptor)
  • Node Version: 22.16.0

I am using the following MathJax configuration:

{
  loader: {
    paths: { mathjax: 'mathjax' },
    load: [ 'adaptors/liteDOM', 'output/svg' ],
    require: [Function: require]
  },
  output: { linebreaks: { inline: true }, font: 'mathjax-stix2' },
  tex: {
    formatError (_, error) {
      throw new Error(error.message)
    }
  },
  startup: {
    ready () {
      // https://github.com/mathjax/MathJax/issues/3185
      const { MmlMath } = MathJax._.core.MmlTree.MmlNodes.math
      const { MmlMstyle } = MathJax._.core.MmlTree.MmlNodes.mstyle
      MmlMath.defaults.scriptsizemultiplier = MmlMstyle.defaults.scriptsizemultiplier = 0.8

      MathJax.startup.defaultReady()
    }
  },
  options: { sre: { locale: 'en', braille: 'nemeth' } },
  svg: { fontCache: 'local', blacker: 0, scale: 1.15 }
}

and loading MathJax via

global.MathJax = this.config // (the above config)
require(this.lib) // (e.g. tex-mml-svg)
await MathJax.startup.promise

Supporting information:

The specific error logged is:

TypeError: Cannot read properties of undefined (reading 'mathmlTree')
    at Rp.applicable (<node_modules>/mathjax/tex-mml-svg.js:1:1687515)
    at Object.run (<node_modules>/mathjax/tex-mml-svg.js:1:1635743)
    at kp.tableToMultiline (<node_modules>/mathjax/tex-mml-svg.js:1:1635908)
    at Ip.table_ (<node_modules>/mathjax/tex-mml-svg.js:1:1672675)
    at Ip.parse (<node_modules>/mathjax/tex-mml-svg.js:1:1671311)
    at Ip.parseList (<node_modules>/mathjax/tex-mml-svg.js:1:1631689)
    at Ip.rows_ (<node_modules>/mathjax/tex-mml-svg.js:1:1671840)
    at Ip.parse (<node_modules>/mathjax/tex-mml-svg.js:1:1671311)
    at Ip.rows_ (<node_modules>/mathjax/tex-mml-svg.js:1:1671688)
    at Ip.parse (<node_modules>/mathjax/tex-mml-svg.js:1:1671311)
Speech generation error: Cannot read properties of null (reading 'indexOf')

Removing the empty mtr resolves the issue (but it does create a slight difference visually).
Right now, to avoid the visual differences, I am using a separate version of the mathml for speech generation in these cases.

// first try normally
// ... MathJax bits ...
// Speech generation error is logged, but no error is thrown
// Try to get speech from node
filterNode(adaptor, node, speech, braille);
// Use lack of speech to detect error condition
if (speech.length === 0 && isMml) {
  const parsed = adaptor.parse(item);
  const toRemove = [];
  let mathNode;
  const filterMath = (node) => {
    const { kind, children } = node;
    if (mathNode === undefined && kind.endsWith('math')) mathNode = node;
    if (Array.isArray(children) && children.length > 0) children.forEach(filterMath);
    else if (kind.endsWith('mtr')) toRemove.push(node);
  };
  filterMath(parsed.body);
  toRemove.forEach(adaptor.remove.bind(adaptor));
  if (mathNode) {
    const speechReadyItem = adaptor.outerHTML(mathNode);
    const speechNode = await MathJax.mathml2svgPromise(speechReadyItem, options);
    filterNode(adaptor, speechNode, speech, braille);
  }
}
// ... and so on

I do not think this problem is in my configuration or usage, but the most relevant part of the script would be here if anyone is looking for more context.

Metadata

Metadata

Assignees

No one assigned

    Labels

    AcceptedIssue has been reproduced by MathJax teamCode ExampleContains an illustrative code example, solution, or work-aroundSREv4

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions