{"record":{"id":"277d7ce661bb12e2","repo":"microsoft/typescript-go","slug":"documentidentifier-expected-string-or-object-got","errorCode":null,"errorMessage":"DocumentIdentifier: expected string or object, got %v","messagePattern":"DocumentIdentifier: expected string or object, got (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/api/proto.go","lineNumber":279,"sourceCode":"\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tisURI := key.String() == \"uri\"\n\t\t\tval, err := dec.ReadToken()\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif isURI {\n\t\t\t\td.URI = lsproto.DocumentUri(val.String())\n\t\t\t}\n\t\t}\n\t\t// Consume the closing brace\n\t\tif _, err := dec.ReadToken(); err != nil {\n\t\t\treturn err\n\t\t}\n\t\treturn nil\n\tdefault:\n\t\treturn fmt.Errorf(\"DocumentIdentifier: expected string or object, got %v\", tok.Kind())\n\t}\n}\n\nfunc (d DocumentIdentifier) ToFileName() string {\n\tif d.URI != \"\" {\n\t\treturn d.URI.FileName()\n\t}\n\treturn d.FileName\n}\n\n// ToURI returns the document URI for this identifier. An explicitly provided URI\n// is returned as-is; a file name is first normalized to an absolute path against\n// cwd before being converted to a URI.\nfunc (d DocumentIdentifier) ToURI(cwd string) lsproto.DocumentUri {\n\tif d.URI != \"\" {\n\t\treturn d.URI\n\t}\n\treturn lsconv.FileNameToDocumentURI(tspath.GetNormalizedAbsolutePath(d.FileName, cwd))","sourceCodeStart":261,"sourceCodeEnd":297,"githubUrl":"https://github.com/microsoft/typescript-go/blob/1bcfa18d79a3be41772223d5c05dfe4480e614ff/internal/api/proto.go#L261-L297","documentation":"DocumentIdentifier.UnmarshalJSONFrom accepts only a JSON string (a file name) or an object with a uri field; any other token kind - number, boolean, null, array - is rejected with the token kind printed. This type appears in file-change notifications and most file-addressed request params.","triggerScenarios":"Sending \"file\": 123, null, true, or an array where the document goes; a numeric or null value slipping through a loosely typed client serializer.","commonSituations":"TypeScript clients with `file: string | number`-style loose types; optional fields defaulting to null; hand-built JSON request strings.","solutions":["Send either \"/abs/path/file.ts\" or {\"uri\":\"file:///abs/path/file.ts\"}","Type the field as string | { uri: string } on the client and lint against anything else","Check for accidental null from optional chaining or unset variables before serializing","Validate outgoing JSON with the type guard below during development"],"exampleFix":"// before\n{ \"file\": null }\n\n// after\n{ \"file\": \"/abs/path/file.ts\" }\n// or\n{ \"file\": { \"uri\": \"file:///abs/path/file.ts\" } }","handlingStrategy":"type-guard","validationCode":"// Go side, before marshalling outgoing params:\nfunc validDocument(d any) bool {\n\tswitch v := d.(type) {\n\tcase string:\n\t\treturn v != \"\"\n\tcase map[string]any:\n\t\t_, ok := v[\"uri\"]\n\t\treturn ok\n\t}\n\treturn false\n}","typeGuard":"// TypeScript client side\nfunction isDocumentIdentifier(v: unknown): v is string | { uri: string } {\n\treturn typeof v === \"string\" ||\n\t\t(typeof v === \"object\" && v !== null && typeof (v as { uri?: unknown }).uri === \"string\");\n}","tryCatchPattern":null,"preventionTips":["Type the field as string | { uri: string } end to end","Guard optional fields against null before serializing","Add a client-side lint/test that round-trips every document payload through the guard"],"tags":["go","json","unmarshal","document-identifier","validation"],"backgroundTag":null,"analyzedSha":"1bcfa18d79a3be41772223d5c05dfe4480e614ff","analyzedAt":"2026-08-16T02:12:00.115Z","schemaVersion":2},"datasetVersion":"2026-08-16T03:17:38.424Z"}