{"record":{"id":"c244ce3f5bd2ac7c","repo":"facebook/flow","slug":"hermesparse-invalid-source-type-other-expected","errorCode":null,"errorMessage":"hermesParse: invalid source_type={other}; expected 0 (unspecified), 1 (script), or 2 (module).","messagePattern":"hermesParse: invalid source_type=(.+?); expected 0 \\(unspecified\\), 1 \\(script\\), or 2 \\(module\\)\\.","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"rust_port/crates/flow_parser_wasm/src/lib.rs","lineNumber":122,"sourceCode":"    source_size: usize,\n    source_filename: *const u8,\n    source_filename_size: usize,\n    enable_components: i32,\n    enable_match: i32,\n    enable_decorators: i32,\n    tokens: i32,\n    allow_return_outside: i32,\n    assert_operator: i32,\n    enable_enums: i32,\n    enable_records: i32,\n    enable_types: i32,\n    source_type: i32,\n    enable_types_pragma_detection: i32,\n    _enable_types_in_comments: i32,\n) -> *mut ParseResult {\n    match source_type {\n        0..=2 => {}\n        other => panic!(\n            \"hermesParse: invalid source_type={other}; expected 0 (unspecified), \\\n             1 (script), or 2 (module).\"\n        ),\n    }\n\n    // SAFETY: The JS bridge in flow-parser/oxidized-src/FlowParser.js wraps\n    // every call to `hermesParse` in a try/finally that allocates `source`\n    // via `_malloc`, copies `source_size` bytes into it, calls this\n    // function, and frees the allocation in `finally`. The pointer is\n    // therefore valid for `source_size` bytes for the duration of this\n    // call. `source_size` is the JS-side `Buffer.length + 1` (UTF-8 source\n    // plus a null terminator), so the slice is in-bounds.\n    let source_bytes = unsafe { std::slice::from_raw_parts(source, source_size) };\n    // Source is null-terminated; exclude the null for parsing\n    let source_len = if source_size > 0 { source_size - 1 } else { 0 };\n    let source_str = match std::str::from_utf8(&source_bytes[..source_len]) {\n        Ok(s) => s,\n        Err(_) => {","sourceCodeStart":104,"sourceCodeEnd":140,"githubUrl":"https://github.com/facebook/flow/blob/f88ac94bcf6992f5d5a158854d94613ebb92c6e6/rust_port/crates/flow_parser_wasm/src/lib.rs#L104-L140","documentation":"hermesParse is the WASM FFI entry point of the Flow parser, taking a long positional argument list. It validates source_type up front and panics for anything outside 0 (unspecified), 1 (script), 2 (module), before touching the source buffer. This guards the FFI boundary against an invalid enum value arriving from the JS bridge.","triggerScenarios":"Calling hermesParse(..., source_type) from JS with a value like 3, -1, undefined (coerced to NaN), or a string; most often caused by a JS bridge and wasm binary from different releases — the JS side passes a new enum value the older wasm rejects — or by a shifted positional argument in a hand-written binding.","commonSituations":"Partial upgrades of the flow-parser npm package where the wasm artifact is stale (bundler cache, mixed lockfile); passing a boolean or a flowconfig-like setting into the source_type slot (it is deep in a ~17-argument positional list); forks that add a new source type in JS without rebuilding the wasm.","solutions":["Pass one of the three allowed constants: 0, 1, or 2 — use 2 for ES modules and 1 for scripts.","Reinstall so JS and wasm match: rm -rf node_modules && npm ci (or clear the bundler's wasm cache).","Count the positional arguments in your call against the wasm signature; an off-by-one shift silently lands a different value in source_type.","If you extended the enum in JS, rebuild the wasm or stop sending the new value to old binaries."],"exampleFix":"// before\nparseResult = FlowParser.parse(source, /* ... */, 3);\n\n// after: 0=unspecified, 1=script, 2=module\nparseResult = FlowParser.parse(source, /* ... */, 2);","handlingStrategy":"validation","validationCode":"// before calling hermesParse\nif (![0, 1, 2].includes(sourceType)) {\n  throw new RangeError(`sourceType must be 0|1|2, got ${sourceType}`);\n}","typeGuard":"const isValidSourceType = (t) =>\n  Number.isInteger(t) && t >= 0 && t <= 2;","tryCatchPattern":null,"preventionTips":["Define named constants SOURCE_TYPE_UNSPECIFIED=0, SCRIPT=1, MODULE=2 and never pass raw literals.","Keep the flow-parser JS package and its wasm artifact from the same release; npm ci after upgrades.","Clear bundler caches of .wasm files when switching versions.","Count positional arguments carefully when hand-writing bindings; a one-slot shift lands in source_type silently."],"tags":["wasm","ffi","parser","argument-validation","javascript","version-mismatch"],"backgroundTag":"invalid-enum-argument","analyzedSha":"f88ac94bcf6992f5d5a158854d94613ebb92c6e6","analyzedAt":"2026-08-20T10:41:37.992Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}