{"record":{"id":"45085a6d895bd113","repo":"microsoft/typescript-go","slug":"w-signature-handle-d-not-found-in-project-regis","errorCode":null,"errorMessage":"%w: signature handle %d not found in project registry","messagePattern":"%w: signature handle (.+?) not found in project registry","errorType":"validation","errorClass":"ErrClientError","httpStatus":null,"severity":"error","filePath":"internal/api/session.go","lineNumber":302,"sourceCode":"\t}\n\tif projectID == \"\" {\n\t\treturn nil, fmt.Errorf(\"%w: empty project ID for signature handle %d\", ErrClientError, handle)\n\t}\n\n\tsd.projectRegistriesMu.RLock()\n\treg := sd.projectRegistries[projectID]\n\tsd.projectRegistriesMu.RUnlock()\n\n\tif reg == nil {\n\t\treturn nil, fmt.Errorf(\"%w: signature handle %d not found (no registry for project %s)\", ErrClientError, handle, projectID)\n\t}\n\n\treg.signatureRegistryMu.RLock()\n\tsig, ok := reg.signatureRegistry[handle]\n\treg.signatureRegistryMu.RUnlock()\n\n\tif !ok {\n\t\treturn nil, fmt.Errorf(\"%w: signature handle %d not found in project registry\", ErrClientError, handle)\n\t}\n\n\treturn sig, nil\n}\n\n// newSignatureResponse registers a signature in the project's registry and returns the response.\nfunc (sd *snapshotData) newSignatureResponse(projectID ProjectID, sig *checker.Signature) *SignatureResponse {\n\tif sig == nil {\n\t\treturn nil\n\t}\n\tresp := &SignatureResponse{\n\t\tId:    sd.registerSignature(projectID, sig),\n\t\tFlags: uint32(sig.Flags()),\n\t}\n\n\tif sig.Declaration() != nil {\n\t\tresp.Declaration = sd.nodeHandleFrom(sig.Declaration())\n\t}","sourceCodeStart":284,"sourceCodeEnd":320,"githubUrl":"https://github.com/microsoft/typescript-go/blob/1bcfa18d79a3be41772223d5c05dfe4480e614ff/internal/api/session.go#L284-L320","documentation":"The project's signature registry exists but the SignatureID is not registered in it: \"signature handle N not found in project registry\". Signature ids are per-checker sequential, so the same number can legitimately belong to different signatures in different projects/snapshots - this error indicates a scope mismatch (stale snapshot, different project, post-release registry) rather than an invalid id format.","triggerScenarios":"Reusing a signature handle after updateSnapshot produced a new snapshot; pairing a signature id with the wrong project; querying after release dropped the snapshot's registries; carrying handles across a server restart.","commonSituations":"Signature-help state cached across document edits; multi-project editors forwarding handles between projects; background workers draining stale request queues after an edit.","solutions":["Re-acquire the signature in the current snapshot before the follow-up call","Bind cached signature handles to (snapshot, project) and invalidate on change/release","Send the project exactly as returned with the signature originally"],"exampleFix":"// before\nawait call(\"signatureFollowUp\", { snapshot, project, signature: staleSig }); // not found\n\n// after\nconst sig = await call(\"getResolvedSignature\", { snapshot, project, file, position });\nif (sig) await call(\"signatureFollowUp\", { snapshot, project, signature: sig.id });","handlingStrategy":"fallback","validationCode":"// TS client: only use signature handles minted in the current snapshot.\nif (cachedSig.snapshot !== snapshot || cachedSig.project !== project) {\n  cachedSig = null;\n}\nif (!cachedSig) {\n  const sig = await call(\"getResolvedSignature\", { snapshot, project, file, position });\n  if (sig) cachedSig = { snapshot, project, id: sig.id };\n}","typeGuard":"const isLiveSignatureHandle = (h: { snapshot: bigint; project: string; id: number }, cur: bigint): h is { snapshot: bigint; project: string; id: number } =>\n  h.snapshot === cur && h.id > 0;","tryCatchPattern":"try {\n  return await call(method, params);\n} catch (e) {\n  if (String(e).includes(\"signature handle\") && String(e).includes(\"not found\")) {\n    const sig = await call(\"getResolvedSignature\", { snapshot: params.snapshot, project: params.project, file, position });\n    if (sig) return await call(method, { ...params, signature: sig.id }); // one retry with fresh handle\n  }\n  throw e;\n}","preventionTips":["Expire signature caches on updateSnapshot/release","Re-resolve signatures at the call site instead of caching ids across edits","Always send the project that came with the signature originally"],"tags":["signature-handle","registry","project","snapshot","stale-handle","client-error"],"backgroundTag":null,"analyzedSha":"1bcfa18d79a3be41772223d5c05dfe4480e614ff","analyzedAt":"2026-08-16T02:12:00.115Z","schemaVersion":2},"datasetVersion":"2026-08-16T03:17:38.424Z"}