{"record":{"id":"750fbedfc5acee75","repo":"facebook/flow","slug":"expected-program-got-deserialized-type","errorCode":null,"errorMessage":"Expected Program, got ${deserialized.type}","messagePattern":"Expected Program, got (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/flow-parser/oxidized-src/FlowParser.js","lineNumber":352,"sourceCode":"      throw syntaxError;\n    }\n\n    const deserialized = new FlowParserDeserializer(\n      programBuffer,\n      flowParseResult_getPositionBuffer(parseResult),\n      flowParseResult_getPositionBufferSize(parseResult),\n      flowParseResult_getStringBuffer(parseResult),\n      FlowParserWASM,\n      options,\n    ).deserialize();\n    if (options.babel === true) {\n      if (deserialized.type !== 'File') {\n        throw new Error(`Expected File, got ${deserialized.type}`);\n      }\n      return deserialized;\n    }\n    if (deserialized.type !== 'Program') {\n      throw new Error(`Expected Program, got ${deserialized.type}`);\n    }\n    const ast = deserialized;\n\n    // Wire→ESTree loc/range normalization. The wire format carries\n    // `rangeStart` / `rangeEnd` on the loc object; ESTree consumers expect a\n    // `range: [start, end]` array on the *node* itself, plus a clean\n    // `loc: { source, start, end }`. This walk is the parser-level analog of\n    // upstream HermesToESTreeAdapter.transform()'s mandatory range conversion\n    // (HermesToESTreeAdapter.js:39 — `node.range = [loc.rangeStart, loc.rangeEnd]`).\n    // Lives here (not in src/index.js) so callers that bypass the public\n    // hermes-parser-compatibility wrapper (e.g. the wasm fixture runner that\n    // tests raw Flow ESTree parity with the OCaml parser) still get the\n    // canonical ESTree loc/range shape.\n    //\n    // Track visited nodes so a malformed AST with a cycle doesn't blow the\n    // stack; track visited locs separately because two nodes can share a loc\n    // reference and we must read `rangeStart`/`rangeEnd` before deleting them.\n    const sourceFilename =","sourceCodeStart":334,"sourceCodeEnd":370,"githubUrl":"https://github.com/facebook/flow/blob/5c865861998a8ccb7dbc82b0c1f511e9ef60c3d9/packages/flow-parser/oxidized-src/FlowParser.js#L334-L370","documentation":"In the same parse() entry point, when the `babel` option is not true, the parser expects the deserialized WASM output root to be an ESTree 'Program' node. Any other root type means the wire-format deserialization did not produce the promised AST shape, so parse() throws to avoid returning an invalid AST to consumers.","triggerScenarios":"Calling parse() without babel:true while the deserialized root node's type is not 'Program' — typically caused by JS wrapper / FlowParserWASM build mismatch or a corrupted deserialized payload.","commonSituations":"Mismatched flow-parser build artifacts, post-processing the options object incorrectly, or consumers deserializing cached AST blobs from a different parser version.","solutions":["Reinstall flow-parser so the wrapper and WASM binary are from the same package version.","If you actually need the Babel 'File' root, pass { babel: true } to parse().","Clear any cached deserialized ASTs produced by older parser versions and re-parse."],"exampleFix":"// before\nconst ast = flow.parse(src); // expects Program, got File\n// after (Babel-style consumers)\nconst ast = flow.parse(src, { babel: true }); // returns File node","handlingStrategy":"type-guard","validationCode":"const ast = flow.parse(src);\nif (ast.type !== 'Program') {\n  throw new Error('Parser returned non-Program root; check flow-parser version integrity');\n}","typeGuard":"const isProgram = (n) => n != null && typeof n === 'object' && n.type === 'Program';","tryCatchPattern":"try {\n  const ast = flow.parse(src);\n} catch (err) {\n  if (String(err.message).startsWith('Expected Program')) {\n    console.error('Use { babel: true } if you need a File root, or reinstall flow-parser');\n  }\n  throw err;\n}","preventionTips":["Match the parse() options to your consumer's expected AST root type.","Reinstall flow-parser after any partial upgrade or lockfile merge.","Add an assertion on ast.type before walking the tree in downstream tooling."],"tags":["ast","wasm","flow-parser","estree"],"backgroundTag":"unexpected-api-response-shape","analyzedSha":"5c865861998a8ccb7dbc82b0c1f511e9ef60c3d9","analyzedAt":"2026-09-08T04:32:53.179Z","contentChangedAt":"2026-09-08T04:32:53.179Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}