microsoft/typescript-go · error

DocumentIdentifier: expected string or object, got %v

Error message

DocumentIdentifier: expected string or object, got %v

What it means

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.

Source

Thrown at internal/api/proto.go:279

			if err != nil {
				return err
			}
			isURI := key.String() == "uri"
			val, err := dec.ReadToken()
			if err != nil {
				return err
			}
			if isURI {
				d.URI = lsproto.DocumentUri(val.String())
			}
		}
		// Consume the closing brace
		if _, err := dec.ReadToken(); err != nil {
			return err
		}
		return nil
	default:
		return fmt.Errorf("DocumentIdentifier: expected string or object, got %v", tok.Kind())
	}
}

func (d DocumentIdentifier) ToFileName() string {
	if d.URI != "" {
		return d.URI.FileName()
	}
	return d.FileName
}

// ToURI returns the document URI for this identifier. An explicitly provided URI
// is returned as-is; a file name is first normalized to an absolute path against
// cwd before being converted to a URI.
func (d DocumentIdentifier) ToURI(cwd string) lsproto.DocumentUri {
	if d.URI != "" {
		return d.URI
	}
	return lsconv.FileNameToDocumentURI(tspath.GetNormalizedAbsolutePath(d.FileName, cwd))

View on GitHub (pinned to 1bcfa18d79)

Solutions

  1. Send either "/abs/path/file.ts" or {"uri":"file:///abs/path/file.ts"}
  2. Type the field as string | { uri: string } on the client and lint against anything else
  3. Check for accidental null from optional chaining or unset variables before serializing
  4. Validate outgoing JSON with the type guard below during development

Example fix

// before
{ "file": null }

// after
{ "file": "/abs/path/file.ts" }
// or
{ "file": { "uri": "file:///abs/path/file.ts" } }
Defensive patterns

Strategy: type-guard

Validate before calling

// Go side, before marshalling outgoing params:
func validDocument(d any) bool {
	switch v := d.(type) {
	case string:
		return v != ""
	case map[string]any:
		_, ok := v["uri"]
		return ok
	}
	return false
}

Type guard

// TypeScript client side
function isDocumentIdentifier(v: unknown): v is string | { uri: string } {
	return typeof v === "string" ||
		(typeof v === "object" && v !== null && typeof (v as { uri?: unknown }).uri === "string");
}

Prevention

When it happens

Trigger: Sending "file": 123, null, true, or an array where the document goes; a numeric or null value slipping through a loosely typed client serializer.

Common situations: TypeScript clients with `file: string | number`-style loose types; optional fields defaulting to null; hand-built JSON request strings.

Related errors


AI-assisted analysis of microsoft/typescript-go@1bcfa18d79 (2026-08-16). Data as JSON: /api/errors/277d7ce661bb12e2. Report an issue: GitHub.