microsoft/typescript-go · error

invalid %s: %s

Error message

invalid %s: %s

What it means

The last-resort decode failure for polymorphic LSP types: after kind-based dispatch narrows the candidate members of a union (e.g. TextEditOrInsertReplaceEdit, WorkspaceFullDocumentDiagnosticReportOrUnchangedDocumentDiagnosticReport, WorkDoneProgressBeginOrReportOrEnd), each candidate is trial-unmarshaled; if all fail, errInvalidValue(typeName, data) reports the type name plus the raw JSON bytes. Unlike errInvalidKind this means the JSON kind was plausible but the contents did not satisfy any member.

Source

Thrown at internal/lsp/lsproto/lsp.go:104

func errNotObject(k json.Kind) error {
	return fmt.Errorf("expected object start, but encountered %v", k)
}

func errNull(field string) error {
	return fmt.Errorf("null value is not allowed for field %q", field)
}

func errMissing(props []string) error {
	return fmt.Errorf("missing required properties: %s", strings.Join(props, ", "))
}

func errInvalidKind(typeName string, got json.Kind) error {
	return fmt.Errorf("invalid %s: got %v", typeName, got)
}

func errInvalidValue(typeName string, data []byte) error {
	return fmt.Errorf("invalid %s: %s", typeName, data)
}

func errLiteralMismatch(typeName string, expected string, got []byte) error {
	return fmt.Errorf("expected %s value %s, got %s", typeName, expected, got)
}

func assertOnlyOne(message string, count int) {
	if count != 1 {
		panic(message)
	}
}

func assertAtMostOne(message string, count int) {
	if count > 1 {
		panic(message)
	}
}

View on GitHub (pinned to 1bcfa18d79)

Solutions

  1. Inspect the raw JSON echoed in the error and compare it against the member shapes of the named union in the LSP spec; fix the missing/invalid nested field (usually a missing `kind` or `range`).
  2. Add the discriminator the union dispatches on (e.g. "kind":"begin" for progress, "kind":"full" for diagnostic reports).
  3. Validate outbound payloads in tests by unmarshaling into the generated lsproto union type before sending.

Example fix

// before: diagnostic report without discriminator
{"resultId":"1","items":[]}
// after
{"kind":"full","resultId":"1","items":[]}
Defensive patterns

Strategy: validation

Validate before calling

// ensure discriminator-bearing unions carry a known `kind`
var knownKinds = map[string]bool{"full": true, "unchanged": true}

func validReport(r map[string]any) bool {
    k, _ := r["kind"].(string)
    return knownKinds[k]
}

Type guard

func hasKnownDiscriminator(v map[string]any, key string, allowed map[string]bool) bool {
    s, ok := v[key].(string)
    return ok && allowed[s]
}

Prevention

When it happens

Trigger: A diagnostic report lacking its required kind discriminator; a TextEdit whose range is absent or malformed; a progress value whose kind is neither begin, report, nor end; a WorkspaceEdit with an unknown structure. Any payload that passes the kind check but fails every candidate's field validation in lsp_generated.go (errMissing/errNull inside trial unmarshals bubble up to this catch-all).

Common situations: Clients that omit discriminator fields like kind; stale code assuming a rename result shape from an older LSP version; AI-generated or hand-written JSON fixtures; middleware that drops nested required fields while transforming payloads.

Related errors


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