{"record":{"id":"a3cbce62fbdb0860","repo":"microsoft/typescript-go","slug":"w-empty-symbol-handle","errorCode":null,"errorMessage":"%w: empty symbol handle","messagePattern":"%w: empty symbol handle","errorType":"validation","errorClass":"ErrClientError","httpStatus":null,"severity":"error","filePath":"internal/api/session.go","lineNumber":238,"sourceCode":"\treg := sd.getOrCreateProjectRegistry(projectID)\n\treg.typeRegistryMu.Lock()\n\tdefer reg.typeRegistryMu.Unlock()\n\texisting := reg.typeRegistry[id]\n\n\tif existing != nil {\n\t\tif existing != t {\n\t\t\tpanic(\"duplicate type\")\n\t\t}\n\t\treturn id\n\t}\n\treg.typeRegistry[id] = t\n\treturn id\n}\n\n// resolveSymbolHandle resolves a symbol handle within the snapshot's registry.\nfunc (sd *snapshotData) resolveSymbolHandle(handle SymbolID) (*ast.Symbol, error) {\n\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}","sourceCodeStart":220,"sourceCodeEnd":256,"githubUrl":"https://github.com/microsoft/typescript-go/blob/1bcfa18d79a3be41772223d5c05dfe4480e614ff/internal/api/session.go#L220-L256","documentation":"A symbol-based request passed SymbolID 0 (\"empty symbol handle\"). 0 is the zero value of SymbolID and is reserved: no symbol ever registers under it, so resolveSymbolHandle rejects it immediately as a client error. In practice 0 arrives from default-initialized params or from the id of a null SymbolResponse - when the server finds no symbol (e.g. getSymbolAtPosition on whitespace or a comment) it returns null, and reading .id of that yields 0/undefined.","triggerScenarios":"Passing a zero-valued symbol field in getTypeOfSymbol/getMembersOfSymbol/getParentOfSymbol params; reusing the id from a getSymbolAtPosition response that was null; JS undefined id coerced to 0 in a struct; forwarding symbol handles before the first symbol query populated them.","commonSituations":"Client skips the null check on symbol lookups at whitespace/keywords; optional-field handling that defaults handles to 0 instead of omitting the request; copy-pasting a follow-up query template without filling the symbol.","solutions":["Null-check symbol responses: only issue symbol-follow-up calls when the response object exists","Guard every handle before sending: reject/omit the call when symbolId is 0, null, or undefined","Treat 0 as 'absent' in your client model (make the field optional, not defaulted)"],"exampleFix":"// before\nconst sym = await call(\"getSymbolAtPosition\", { snapshot, project, file, position });\nawait call(\"getTypeOfSymbol\", { snapshot, project, symbol: sym?.id ?? 0 }); // empty symbol handle\n\n// after\nconst sym = await call(\"getSymbolAtPosition\", { snapshot, project, file, position });\nif (sym) {\n  await call(\"getTypeOfSymbol\", { snapshot, project, symbol: sym.id });\n}","handlingStrategy":"type-guard","validationCode":"// TS client: check the handle before the request.\nif (!symbolId) { // covers 0, undefined, null\n  return; // nothing found earlier - skip the follow-up call\n}\nawait call(\"getTypeOfSymbol\", { snapshot, project, symbol: symbolId });","typeGuard":"const isNonEmptySymbolHandle = (id: number | bigint | undefined | null): id is number =>\n  (typeof id === \"number\" || typeof id === \"bigint\") && id !== 0 && id > 0;","tryCatchPattern":null,"preventionTips":["Treat a null SymbolResponse as 'no symbol' and short-circuit follow-up queries","Model symbol ids as optional fields, never zero-defaulted numbers","Centralize one guard (id > 0) used by every symbol-taking request helper"],"tags":["symbol-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"}