{"record":{"id":"6fe18a259713592b","repo":"mozilla/pdf.js","slug":"invalid-token-in-form-code","errorCode":null,"errorMessage":"Invalid token in Form code","messagePattern":"Invalid token in Form code","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/core/xfa/formcalc_parser.js","lineNumber":989,"sourceCode":"    return { special: \"break\" };\n  }\n}\n\nclass ContinueDecl extends Leaf {\n  dump() {\n    return { special: \"continue\" };\n  }\n}\n\nclass Parser {\n  constructor(code) {\n    this.lexer = new Lexer(code);\n  }\n\n  parse() {\n    const [tok, decls] = this.parseExprList();\n    if (tok.id !== TOKEN.eof) {\n      throw new Error(\"Invalid token in Form code\");\n    }\n    return decls;\n  }\n\n  parseExprList() {\n    const expressions = [];\n    let tok = null,\n      expr;\n    while (true) {\n      [tok, expr] = this.parseExpr(tok);\n      if (!expr) {\n        return [tok, new ExprList(expressions)];\n      }\n      expressions.push(expr);\n    }\n  }\n\n  parseExpr(tok) {","sourceCodeStart":971,"sourceCodeEnd":1007,"githubUrl":"https://github.com/mozilla/pdf.js/blob/5903d58d58e4dd9ce6ffa3834aea8480f06b4ada/src/core/xfa/formcalc_parser.js#L971-L1007","documentation":"Thrown by Parser.parse() (top-level entry of the FormCalc parser) when the expression list was consumed but the lexer has not reached EOF. Any leftover, non-whitespace token after a complete declaration/expression list means the source is not a well-formed FormCalc program. Unlike the named Errors.* messages, this one is an inline literal string.","triggerScenarios":"A FormCalc script where valid declarations are followed by stray tokens (e.g. an orphan keyword, a second top-level construct the grammar does not allow, or trailing characters after 'endfunc'/'endif'). Reached when PDF.js parses an XFA form's 'script' or 'calc' content.","commonSituations":"Two statements concatenated without a legal separator; a trailing fragment left after deleting a declaration mid-edit; a generator that appends extra tokens; truncated or concatenated script content in a damaged XFA packet.","solutions":["Locate the byte offset of the unexpected token (the lexer tracks position) and remove or restructure the trailing tokens so the program ends cleanly at EOF.","Ensure each top-level declaration (var/func/if/for/while/foreach/block) is complete and that no statement spills past its terminator.","Re-serialize the XFA form script through a validated FormCalc authoring/export tool.","Isolate the script string and run it through a FormCalc lint/parse pass before binding it to the XFA template."],"exampleFix":"// before (two top-level forms jammed together)\nvar a = 1 var b = 2\n// after\nvar a = 1\nvar b = 2","handlingStrategy":"validation","validationCode":"// Cheap pre-check: the script should parse to exactly one expression list\n// ending at EOF. Wrap the parser and treat any throw as 'do not bind'.\nfunction isParseableFormCalc(src) {\n  try { new FormCalcParser(src).parse(); return true; }\n  catch { return false; }\n}","typeGuard":null,"tryCatchPattern":"try {\n  const decls = new Parser(src).parse();\n  bindDecls(xfaNode, decls);\n} catch (e) {\n  if (e instanceof Error && /Invalid token in Form code/.test(e.message)) {\n    console.warn(\"FormCalc program has trailing/invalid tokens; skipping\", e.message);\n    return;\n  }\n  throw e;\n}","preventionTips":["Run FormCalc scripts through a parse/lint pass before binding.","Ensure each top-level construct is complete and nothing trails after the last terminator.","Re-serialize XFA packets with a validated tool."],"tags":["xfa","formcalc","parser","syntax","eof"],"backgroundTag":null,"analyzedSha":"5903d58d58e4dd9ce6ffa3834aea8480f06b4ada","analyzedAt":"2026-08-13T02:28:27.364Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}