{"record":{"id":"5e9855a71e5e76ba","repo":"microsoft/typescript-go","slug":"w-empty-project-id-for-signature-handle-d","errorCode":null,"errorMessage":"%w: empty project ID for signature handle %d","messagePattern":"%w: empty project ID for signature handle (.+?)","errorType":"validation","errorClass":"ErrClientError","httpStatus":null,"severity":"error","filePath":"internal/api/session.go","lineNumber":286,"sourceCode":"\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 {\n\t\treturn nil, fmt.Errorf(\"%w: signature handle %d not found in project registry\", ErrClientError, handle)\n\t}\n","sourceCodeStart":268,"sourceCodeEnd":304,"githubUrl":"https://github.com/microsoft/typescript-go/blob/1bcfa18d79a3be41772223d5c05dfe4480e614ff/internal/api/session.go#L268-L304","documentation":"A signature-based request supplied a SignatureID but no ProjectID, so resolveSignatureHandle fails with \"empty project ID for signature handle N\". Signature ids are sequential per checker (per project), so - exactly like type handles - a signature handle is only meaningful together with the project it was created in, and the project parameter is mandatory in every request that carries a signature handle.","triggerScenarios":"Omitting project from params when querying a signature's parameters, target, or declaration; a client struct defaulting project to \"\"; copying the signature id out of a SignatureResponse without its project context.","commonSituations":"Client helpers that forward handles without project state; refactor dropping the project field; assuming signatures are snapshot-global like symbols (they are project-scoped).","solutions":["Always send the project that the signature handle came from","Store {projectId, signatureId} as an atomic pair in client state","If project is unknown, take it from the SymbolResponse.Project or the response that produced the signature"],"exampleFix":"// before\nawait call(\"getTargetOfSignature\"-style follow-up, { snapshot, signature: sigId }); // empty project ID\n\n// after\nawait call(\"someSignatureFollowUp\", { snapshot, project: sigId.project, signature: sigId.id });","handlingStrategy":"validation","validationCode":"// TS client: require project whenever a signature handle is sent.\nfunction assertSignatureRequest(params: { project?: string; signature?: number }) {\n  if (params.signature !== undefined) {\n    if (!params.project) throw new Error(\"signature handle requires its originating project\");\n    if (!(params.signature > 0)) throw new Error(\"signature handle must be > 0\");\n  }\n}","typeGuard":"const isProjectScopedSignatureHandle = (h: { project?: string; id?: number } | null | undefined): h is { project: string; id: number } =>\n  !!h && typeof h.project === \"string\" && h.project.length > 0 && typeof h.id === \"number\" && h.id > 0;","tryCatchPattern":null,"preventionTips":["Carry signature handles as {project, id} pairs, never bare numbers","Take the project from the SignatureResponse that produced the handle","Type and signature handles are project-scoped; only symbol handles are snapshot-scoped"],"tags":["signature-handle","project","validation","required-field","client-error"],"backgroundTag":null,"analyzedSha":"1bcfa18d79a3be41772223d5c05dfe4480e614ff","analyzedAt":"2026-08-16T02:12:00.115Z","schemaVersion":2},"datasetVersion":"2026-08-16T03:17:38.424Z"}