{"record":{"id":"02cc587cb77102b4","repo":"zed-industries/zed","slug":"incorrect-proto-inlay-hint-message-no-resolve-sta","errorCode":null,"errorMessage":"incorrect proto inlay hint message: no resolve state in hint {message_hint:?}","messagePattern":"incorrect proto inlay hint message: no resolve state in hint (.+?)","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/project/src/lsp_command.rs","lineNumber":3469,"sourceCode":"        buffer\n            .update(&mut cx, |buffer, _| {\n                buffer.wait_for_version(deserialize_version(&message.version))\n            })\n            .await?;\n\n        let completions = message\n            .completions\n            .into_iter()\n            .map(LspStore::deserialize_completion)\n            .collect::<Result<Vec<_>>>()?;\n\n        Ok(CoreCompletionResponse {\n            completions,\n            is_incomplete: !message.can_reuse,\n        })\n    }\n\n    fn buffer_id_from_proto(message: &proto::GetCompletions) -> Result<BufferId> {\n        BufferId::new(message.buffer_id)\n    }\n}\n\npub struct ParsedCompletionEdit {\n    pub replace_range: Range<Anchor>,\n    pub insert_range: Option<Range<Anchor>>,\n    pub new_text: String,\n}\n\npub(crate) fn parse_completion_text_edit(\n    edit: &lsp::CompletionTextEdit,\n    snapshot: &BufferSnapshot,\n) -> Option<ParsedCompletionEdit> {\n    let (replace_range, insert_range, new_text) = match edit {\n        lsp::CompletionTextEdit::Edit(edit) => (edit.range, None, &edit.new_text),\n        lsp::CompletionTextEdit::InsertAndReplace(edit) => {\n            (edit.replace, Some(edit.insert), &edit.new_text)","sourceCodeStart":3451,"sourceCodeEnd":3487,"githubUrl":"https://github.com/zed-industries/zed/blob/9d272b036335401f339d024ea94968fd51016c40/crates/project/src/lsp_command.rs#L3451-L3487","documentation":"Inlay hints are serialized into proto messages when exchanged between processes. proto_to_project_hint converts one back and requires the resolve_state field (resolved/resolvable state plus optional LSP data) to be present; a hint without it panics as 'incorrect proto inlay hint message'. The serializer always sets resolve_state, so receiving one without it indicates a mismatched or older proto definition on the peer, or a buggy/hand-built message.","triggerScenarios":"Decoding InlayHint messages whose resolve_state is None: a collaborator/remote peer built with a different version of the proto crate, a hand-rolled server omitting the field, or test code constructing proto::InlayHint directly without setting resolve_state.","commonSituations":"Version skew between editor and collaborator/server builds after an inlay-hints proto change; hand-written test fixtures; forks that add proto fields without populating required ones.","solutions":["Update both sides (client and server/collaborators) to matching versions so proto schemas and serialization agree","When constructing proto::InlayHint yourself, always populate resolve_state - mirror what the to_proto serializer emits","If you own the converter, return an anyhow error for missing resolve_state and skip the malformed hint instead of panicking","Add proto round-trip tests (project -> proto -> project) for inlay hints to catch missing fields in CI"],"exampleFix":"// before: hand-built message missing required field\nlet hint = proto::InlayHint { label, position, resolve_state: None, ..Default::default() };\nlet hint = proto_to_project_hint(hint); // panics\n\n// after: always set resolve_state\nlet hint = proto::InlayHint {\n    label,\n    position,\n    resolve_state: Some(proto::InlayHintResolveState {\n        state: proto::ResolveState::Resolved as i32,\n        lsp_resolve_state: None,\n    }),\n    ..Default::default()\n};\nlet hint = proto_to_project_hint(hint)?;","handlingStrategy":"validation","validationCode":"// drop malformed hints before conversion instead of panicking\nlet hints: Vec<_> = message_hints\n    .into_iter()\n    .filter(|hint| hint.resolve_state.is_some())\n    .collect();\nlet converted = hints\n    .into_iter()\n    .map(proto_to_project_hint)\n    .collect::<anyhow::Result<Vec<_>>>()?;","typeGuard":"fn is_valid_proto_hint(hint: &proto::InlayHint) -> bool {\n    hint.resolve_state.is_some()\n}","tryCatchPattern":null,"preventionTips":["Pin proto crate versions across every binary that exchanges these messages","Round-trip test proto conversions for every message type with required fields","Treat missing required proto fields as data bugs: log and skip them instead of panicking in converters"],"tags":["lsp","inlay-hints","proto","serialization","zed"],"backgroundTag":"proto-validation-failed","analyzedSha":"9d272b036335401f339d024ea94968fd51016c40","analyzedAt":"2026-08-20T19:29:52.058Z","contentChangedAt":"2026-08-20T19:29:52.058Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}