dianping/cat · error · PHP.ParseError

syntax error, unexpected + terminals[tokenId] + expectedStr

Error message

syntax error, unexpected  + terminals[tokenId] + expectedString (e.g. ', expecting ' + expected.join(' or '))

What it means

PHP.ParseError thrown by the generated LALR parser tables inside the ACE PHP worker (worker-php.js, error at line 2403 in the yyerror/reporting path). It means the token sequence is grammatically invalid PHP: the parser computed the set of terminals acceptable in the current state, listed them as 'expecting ...', and reports the unexpected token it actually got, along with the start line of the offending statement.

Source

Thrown at cat-home/src/main/webapp/assets/js/editor/worker-php.js:2403

                            && (yyn = yybase[ state + this.YYNLSTATES] + i)
                            && yyn < this.YYLAST && yycheck[ yyn ] == i
                        ) {
                            if (yyaction[ yyn ] != this.YYUNEXPECTED) {
                                if (expected.length == 4) {
                                    expected = [];
                                    break;
                                }

                                expected.push( this.terminals[ i ] );
                            }
                        }
                    }

                    var expectedString = '';
                    if (expected.length) {
                        expectedString = ', expecting ' + expected.join(' or ');
                    }
                    throw new PHP.ParseError('syntax error, unexpected ' + terminals[ tokenId ] + expectedString, this.startAttributes['startLine']);
                } else {
                    return this.startAttributes['startLine'];
                }

            }

            if (state < this.YYNLSTATES)
                break;
            yyn = state - this.YYNLSTATES;
        }
    }
};

PHP.ParseError = function( msg, line ) {
    this.message = msg;
    this.line = line;
};

View on GitHub (pinned to e815e74d4c)

Solutions

  1. Look at the reported start line and the 'expecting' list: insert or fix the listed punctuation/token (most often a missing semicolon, brace, or parenthesis).
  2. If the code targets a newer PHP than the worker understands, treat the annotation as a false positive and upgrade the PHP worker/parser tables.
  3. Check the previous line as well — LALR errors frequently surface one token after the actual mistake.
  4. Run php -l on the file to cross-check the real PHP error position.

Example fix

// before
<?php
$a = 1
echo $a;

// after
<?php
$a = 1;
echo $a;
Defensive patterns

Strategy: try-catch

Validate before calling

// Cheap pre-flight in the editor host before shipping PHP to the worker:
function plausiblyParseable(src) {
  if (!/^<\?php|<\?=/m.test(src)) return false;
  const bal = (s, a, b) => (s.split(a).length - 1) - (s.split(b).length - 1);
  return bal(src, '{', '}') === 0 && bal(src, '(', ')') === 0;
}

Type guard

function isParseError(ex) {
  return ex instanceof PHP.ParseError;
}

Try / catch

try {
  new PHP.Parser(lexer, ast).parse(src);
} catch (ex) {
  if (isParseError(ex)) {
    annotate({ line: ex.line, message: ex.message }); // line lives on the error
  } else throw ex;
}

Prevention

When it happens

Trigger: Any syntactically broken PHP fed to the worker: missing ';' before a statement, unbalanced braces/parens, 'foreach (array as' with missing variable, using a reserved word as a function name. The parser reaches a state where the lookahead tokenId has no action, builds the 'expected' list from this.terminals, and throws at line 2409.

Common situations: Live typing in the ACE PHP editor (the worker parses on each change, so half-written statements routinely produce this), pasted PHP with smart quotes, PHP 8 syntax (match, arrow fns, attributes) fed to an old parser that only knows PHP 5.x, or a file whose opening '<?php' tag is missing.

Related errors


AI-assisted analysis of dianping/cat@e815e74d4c (2026-08-14). Data as JSON: /api/errors/6f4f8ba077ab9930. Report an issue: GitHub.