{"record":{"id":"42a08d9a51675cd7","repo":"microsoft/typescript-go","slug":"w-empty-type-handle","errorCode":null,"errorMessage":"%w: empty type handle","messagePattern":"%w: empty type handle","errorType":"validation","errorClass":"ErrClientError","httpStatus":null,"severity":"error","filePath":"internal/api/session.go","lineNumber":255,"sourceCode":"\tif handle == 0 {\n\t\treturn nil, fmt.Errorf(\"%w: empty symbol handle\", ErrClientError)\n\t}\n\n\tsd.symbolRegistryMu.RLock()\n\tsymbol, ok := sd.symbolRegistry[handle]\n\tsd.symbolRegistryMu.RUnlock()\n\n\tif !ok {\n\t\treturn nil, fmt.Errorf(\"%w: symbol handle %d not found in snapshot registry\", ErrClientError, handle)\n\t}\n\n\treturn symbol, nil\n}\n\n// resolveTypeHandle resolves a type handle within the project's registry.\nfunc (sd *snapshotData) resolveTypeHandle(projectID ProjectID, handle TypeID) (*checker.Type, error) {\n\tif handle == 0 {\n\t\treturn nil, fmt.Errorf(\"%w: empty type handle\", ErrClientError)\n\t}\n\tif projectID == \"\" {\n\t\treturn nil, fmt.Errorf(\"%w: empty project ID for type 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: 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 {","sourceCodeStart":237,"sourceCodeEnd":273,"githubUrl":"https://github.com/microsoft/typescript-go/blob/1bcfa18d79a3be41772223d5c05dfe4480e614ff/internal/api/session.go#L237-L273","documentation":"A type-based request passed TypeID 0 (\"empty type handle\"). TypeID 0 is the zero value and never maps to a registered checker.Type, so resolveTypeHandle rejects it before any registry lookup. It almost always means the client sent a default-initialized field or took the id from a null TypeResponse (type-returning calls return null when there is nothing to report, e.g. getTypeOfSymbol on a symbol with no type).","triggerScenarios":"Passing 0 in getSymbolOfType/getTargetOfType/getTypesOfType/getSignaturesOfType params; reading .type?.id of a response where the type was null and letting it default to 0; undefined type field serialized as 0; forwarding a handle before the originating query populated it.","commonSituations":"Client pipelines that chain type queries without null checks; optional type fields in client structs defaulting to zero; template request objects reused across queries.","solutions":["Null-check type responses before chaining further type queries","Validate the handle is a positive integer before sending; skip or omit the call when it is 0","Model type handles as optional in the client so absence is explicit rather than coerced to 0"],"exampleFix":"// before\nconst t = await call(\"getTypeOfSymbol\", { snapshot, project, symbol });\nawait call(\"getTargetOfType\", { snapshot, project, type: t?.id ?? 0 }); // empty type handle\n\n// after\nconst t = await call(\"getTypeOfSymbol\", { snapshot, project, symbol });\nif (t) {\n  await call(\"getTargetOfType\", { snapshot, project, type: t.id });\n}","handlingStrategy":"type-guard","validationCode":"// TS client: skip the follow-up when the type handle is empty.\nif (!typeId) { // 0/undefined/null\n  return;\n}\nawait call(\"getTargetOfType\", { snapshot, project, type: typeId });","typeGuard":"const isNonEmptyTypeHandle = (id: number | undefined | null): id is number =>\n  typeof id === \"number\" && Number.isInteger(id) && id > 0;","tryCatchPattern":null,"preventionTips":["Null-check TypeResponse before chaining getTargetOfType/getTypesOfType/etc.","Keep type ids optional in client models; absence means 'skip', not 0","Use a shared isNonEmptyTypeHandle guard in every request helper"],"tags":["type-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"}