{"record":{"id":"f240c5dbd1fe66c2","repo":"microsoft/typescript-go","slug":"w-empty-signature-handle","errorCode":null,"errorMessage":"%w: empty signature handle","messagePattern":"%w: empty signature handle","errorType":"validation","errorClass":"ErrClientError","httpStatus":null,"severity":"error","filePath":"internal/api/session.go","lineNumber":283,"sourceCode":"\tif reg == nil {\n\t\treturn nil, fmt.Errorf(\"%w: type handle %d not found (no registry for project %s)\", ErrClientError, handle, projectID)\n\t}\n\n\treg.typeRegistryMu.RLock()\n\tt, ok := reg.typeRegistry[handle]\n\treg.typeRegistryMu.RUnlock()\n\n\tif !ok {\n\t\treturn nil, fmt.Errorf(\"%w: type handle %d not found in project registry\", ErrClientError, handle)\n\t}\n\n\treturn t, nil\n}\n\n// resolveSignatureHandle resolves a signature handle within the project's registry.\nfunc (sd *snapshotData) resolveSignatureHandle(projectID ProjectID, handle SignatureID) (*checker.Signature, error) {\n\tif handle == 0 {\n\t\treturn nil, fmt.Errorf(\"%w: empty signature handle\", ErrClientError)\n\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 {","sourceCodeStart":265,"sourceCodeEnd":301,"githubUrl":"https://github.com/microsoft/typescript-go/blob/1bcfa18d79a3be41772223d5c05dfe4480e614ff/internal/api/session.go#L265-L301","documentation":"A signature-based request passed SignatureID 0 (\"empty signature handle\"). SignatureID 0 is the zero value and never maps to a registered checker.Signature; resolveSignatureHandle rejects it up front as a client error. Typically the client sent a default-initialized field or took the id from a null/absent signature (getSignaturesOfType returns no entries when the type has none, and getResolvedSignature can return null when no call target resolves).","triggerScenarios":"Passing 0 in getResolvedSignature follow-ups or signature-parameter queries; using the id of a null SignatureResponse (e.g. getResolvedSignature on a non-call expression); undefined signature field serialized as 0.","commonSituations":"Signature-help UIs chaining parameter/type queries without checking that a signature was found; optional fields defaulting to zero; reusing param templates.","solutions":["Null-check signature responses and absent parameter lists before issuing follow-ups","Validate the handle is a positive integer before sending; skip the call when 0","Make signature handles optional in the client model so 'no signature' is distinct from 'signature 0'"],"exampleFix":"// before\nconst sig = await call(\"getResolvedSignature\", { snapshot, project, file, position });\nawait call(\"getTypeOfSymbol\", { snapshot, project, symbol: sig?.id ? 0 : 0 }); // empty handle\n\n// after\nconst sig = await call(\"getResolvedSignature\", { snapshot, project, file, position });\nif (sig) {\n  // sig.id is non-zero; use sig.parameters symbols etc.\n}","handlingStrategy":"type-guard","validationCode":"// TS client: skip follow-ups when the signature handle is empty.\nif (!signatureId) { // 0/undefined/null\n  return; // no signature resolved at this position\n}\nawait call(\"signatureFollowUp\", { snapshot, project, signature: signatureId });","typeGuard":"const isNonEmptySignatureHandle = (id: number | bigint | undefined | null): id is number =>\n  (typeof id === \"number\" || typeof id === \"bigint\") && id !== 0 && id > 0;","tryCatchPattern":null,"preventionTips":["Null-check getResolvedSignature/getSignaturesOfType results before follow-ups","Model signature ids as optional, not zero-defaulted","One shared guard (id > 0) across all signature-taking request helpers"],"tags":["signature-handle","validation","zero-value","null-response","client-error"],"backgroundTag":null,"analyzedSha":"1bcfa18d79a3be41772223d5c05dfe4480e614ff","analyzedAt":"2026-08-16T02:12:00.115Z","schemaVersion":2},"datasetVersion":"2026-08-16T03:17:38.424Z"}