{"record":{"id":"da232530d6d888e3","repo":"microsoft/typescript-go","slug":"invalid-node-handle-handle","errorCode":null,"errorMessage":"Invalid node handle: ${handle}","messagePattern":"Invalid node handle: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"_packages/native-preview/src/api/node/node.ts","lineNumber":328,"sourceCode":"}\r\n\r\n/**\r\n * Parsed components of a node handle.\r\n */\r\nexport interface ParsedNodeHandle {\r\n    index: number;\r\n    kind: SyntaxKind;\r\n    path: Path;\r\n}\r\n\r\n/**\r\n * Parse a node handle string into its components.\r\n * Handle format: \"index.kind.path\" where path may contain dots.\r\n */\r\nexport function parseNodeHandle(handle: string): ParsedNodeHandle {\r\n    const firstDot = handle.indexOf(\".\");\r\n    if (firstDot === -1) {\r\n        throw new Error(`Invalid node handle: ${handle}`);\r\n    }\r\n    const secondDot = handle.indexOf(\".\", firstDot + 1);\r\n    if (secondDot === -1) {\r\n        throw new Error(`Invalid node handle: ${handle}`);\r\n    }\r\n\r\n    return {\r\n        index: parseInt(handle.slice(0, firstDot), 10),\r\n        kind: parseInt(handle.slice(firstDot + 1, secondDot), 10) as SyntaxKind,\r\n        path: handle.slice(secondDot + 1) as Path,\r\n    };\r\n}\r\n\r\n/**\r\n * Decode binary-encoded AST data into a Node.\r\n * Works for any binary-encoded node, including synthetic nodes\r\n * (e.g. from typeToTypeNode) that don't have a source file.\r\n */\r","sourceCodeStart":310,"sourceCodeEnd":346,"githubUrl":"https://github.com/microsoft/typescript-go/blob/1bcfa18d79a3be41772223d5c05dfe4480e614ff/_packages/native-preview/src/api/node/node.ts#L310-L346","documentation":"Thrown by parseNodeHandle when the handle string contains no '.' at all. Node handles have the format \"index.kind.path\" (path may itself contain dots); the first indexOf('.') failing means the input is a single segment - e.g., a bare numeric id, a filename, or some other identifier that is not a handle.","triggerScenarios":"Passing a raw file path, symbol name, numeric node index, or arbitrary user string where a node handle is expected; handles truncated to their first segment; strings sourced from a different tool with its own id format.","commonSituations":"Plumbing tsgo API ids (symbol ids, project ids) into functions that expect node handles; debug tooling that reconstructs handles by string concatenation and drops segments; deserialization bugs stripping dotted suffixes.","solutions":["Only pass handles obtained from RemoteNode.id / API responses - never construct them by hand","Validate the shape first (must contain at least two '.') and reject early with your own error message","If you only have an index, use the appropriate API (node lookup by index) instead of forging a handle","Check for truncation where the handle was stored/transported and its tail was cut off"],"exampleFix":"// before\nconst parsed = parseNodeHandle(userInput); // e.g. '42' or 'main.ts' -> throws\n\n// after\nconst NODE_HANDLE_RE = /^\\d+\\.\\d+\\..+$/;\nif (!NODE_HANDLE_RE.test(userInput)) {\n    throw new TypeError(`Not a node handle: ${userInput}`);\n}\nconst parsed = parseNodeHandle(userInput);","handlingStrategy":"type-guard","validationCode":"// Require the full 'index.kind.path' shape before parsing\nconst NODE_HANDLE_RE = /^\\d+\\.\\d+\\..+$/;\nif (!NODE_HANDLE_RE.test(handle)) {\n    throw new TypeError(`Not a node handle (expected 'index.kind.path'): ${handle}`);\n}\nconst parsed = parseNodeHandle(handle);","typeGuard":"const isNodeHandle = (s: string): boolean => /^\\d+\\.\\d+\\..+$/.test(s);","tryCatchPattern":"try {\n    parsed = parseNodeHandle(value);\n} catch (e) {\n    if (e instanceof Error && e.message.startsWith('Invalid node handle')) {\n        // wrong kind of identifier passed: fail with context instead of propagating\n        throw new TypeError(`Expected a node handle from RemoteNode.id, got: ${value}`);\n    }\n    throw e;\n}","preventionTips":["Treat node handles as opaque API-produced strings - never synthesize them","Keep symbol ids, file paths, and node handles in distinct typed variables","Validate handle shape at deserialization boundaries (storage, IPC, logs)"],"tags":["api","node-handle","parsing","type-guard","native-preview"],"backgroundTag":null,"analyzedSha":"1bcfa18d79a3be41772223d5c05dfe4480e614ff","analyzedAt":"2026-08-16T02:12:00.115Z","schemaVersion":2},"datasetVersion":"2026-08-16T03:17:38.424Z"}