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
- 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.
- Verify client and server come from the same build/version before querying type-at-pos.
- 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.
- 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
- Keep client and server binaries on the same build; stop stale servers after upgrades before querying type-at-pos.
- Round-trip test any change to the server-side JSON emitter through serde_json.
- Never feed hand-built strings into RawValue without strict JSON validation.
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
- Can't decode daemon parameters: {}
- invalid file index
- hh_load_heap: invalid magic number
- hh_load_heap: invalid shard count
- failed to write json errors
AI-assisted analysis of facebook/flow@f88ac94bcf (2026-08-20).
Data as JSON: /api/errors/4f8d299c60c49a60.
Report an issue: GitHub.