facebook/flow · error

type-at-pos: server payload is valid JSON

Error message

type-at-pos: server payload is valid JSON

What it means

`flow type-at-pos` asks the flow server for the types at a position; the server returns an already-serialized JSON string that the client wraps with `serde_json::value::RawValue::from_string` so duplicate keys survive. This expect panics when the server's `types` payload is not strictly valid JSON — i.e., the server-side serializer (`ty_debug::json_of_utility`) emitted malformed output such as bare NaN/Infinity, trailing data, or bad escapes. Duplicate keys are legal here; invalid syntax is not.

Source

Thrown at rust_port/crates/flow_cli/src/type_at_pos_command.rs:163

    file_contents: Option<String>,
    pretty: bool,
    strip_root: Option<&str>,
    response: server_prot::response::infer_type::T,
) {
    let server_prot::response::infer_type::T {
        loc,
        tys,
        refining_locs,
        refinement_invalidated: _,
        documentation,
    } = response;
    match tys {
        server_prot::response::infer_type::Payload::Json(types) => {
            // Wrap the server's pre-serialized "types" JSON as a `RawValue` so the
            // duplicate keys produced by `ty_debug::json_of_utility` survive the
            // round-trip — `serde_json::Map` would deduplicate them.
            let types_raw = serde_json::value::RawValue::from_string(types)
                .expect("type-at-pos: server payload is valid JSON");
            let offset_table = file_contents
                .as_deref()
                .map(flow_parser::offset_utils::OffsetTable::make);
            let loc_json =
                flow_common::reason::json_of_loc(strip_root, false, offset_table.as_ref(), &loc);
            let deprecated = error_utils::deprecated_json_props_of_loc(strip_root, &loc);
            // Fields are declared in alphabetical order so the serde-derived
            // serializer emits them in the same order OCaml's `Hh_json`
            // (`sort_keys=true`) does.
            #[derive(serde::Serialize)]
            struct OuterResponse<'a> {
                #[serde(skip_serializing_if = "Option::is_none")]
                documentation: Option<&'a str>,
                end: &'a serde_json::Value,
                endline: &'a serde_json::Value,
                line: &'a serde_json::Value,
                loc: &'a serde_json::Value,
                path: &'a serde_json::Value,

View on GitHub (pinned to f88ac94bcf)

Solutions

  1. Stop the stale server (`flow stop`, or remove the flow temp dir) so a fresh server from the same build as the client starts, then retry.
  2. Verify client and server come from the same build/version before querying type-at-pos.
  3. Capture the raw payload (enable logging on the client) and validate it with `jq` or `serde_json::from_str::<serde_json::Value>` to identify the malformed fragment; fix the server-side `json_of_utility` path.
  4. If you patched the server serializer, add a round-trip test through serde_json so invalid output is caught server-side.

Example fix

// before
let types_raw = serde_json::value::RawValue::from_string(types)
    .expect("type-at-pos: server payload is valid JSON");

// after
let types_raw = match serde_json::value::RawValue::from_string(types) {
    Ok(v) => v,
    Err(e) => {
        eprintln!("type-at-pos: server sent invalid JSON ({e}); restart the flow server and retry");
        std::process::exit(1);
    }
};
Defensive patterns

Strategy: validation

Validate before calling

// Validate the server payload before wrapping it as a RawValue
fn payload_is_valid_json(types: &str) -> bool {
    serde_json::from_str::<serde_json::Value>(types).is_ok()
}

Try / catch

match serde_json::value::RawValue::from_string(types) {
    Ok(raw) => raw,
    Err(e) => {
        eprintln!("server sent invalid JSON ({e}); restart the flow server and retry");
        std::process::exit(1);
    }
}

Prevention

When it happens

Trigger: A version-skewed server whose type serializer differs from the client's expectations; a server bug where some type node serializes with invalid JSON syntax; a truncated payload because the server crashed or the connection dropped mid-response; a custom/mock server returning hand-built strings.

Common situations: A stale flow server still running after the client binary was upgraded (build-id check not hit yet); running against a patched or instrumented server build; local development changes to the server-side JSON emitter that were not round-trip tested.

Understand the failure class

Background: JSON parse error: "Unexpected token" / "not valid JSON" / "failed to parse" — what JSON parsers are really complaining about — this error's family across 45 libraries.

Related errors


AI-assisted analysis of facebook/flow@f88ac94bcf (2026-08-20). Data as JSON: /api/errors/4f8d299c60c49a60. Report an issue: GitHub.