PostToolUse:Edit IDE diagnostics: 'code' field returns literal '[object Object]' instead of the diagnostic code string

Resolved 💬 1 comment Opened May 14, 2026 by Abdallah01 Closed Jun 12, 2026

Summary

When the VS Code extension surfaces IDE diagnostics back to the model via the PostToolUse:Edit hook (the <ide_diagnostics> block in the tool result), the per-diagnostic code field is a literal string "[object Object]" instead of the actual analyzer code (e.g. "unused_import", "discarded_futures", "undefined_method").

This is a JS-side stringification bug: the underlying Diagnostic.code from the language server is being sent through String(code) (or template-literal coercion) without checking whether code is the LSP "object form" {value: string | number, target: Uri}.

Reproduction

  1. Open a Dart file in VS Code (Dart Code extension installed and active).
  2. Use the Claude Code Edit tool to introduce a Dart analyzer warning — e.g., remove a use of an imported symbol so unused_import fires, or add async to a function that awaits nothing so unnecessary_async fires.
  3. Inspect the PostToolUse:Edit hook output that comes back to the model. The <ide_diagnostics> block contains entries like:
{
  "filePath": "/c:/src/.../my_file.dart",
  "line": 42,
  "column": 5,
  "message": "Unused import: 'package:flutter/foundation.dart'.\nTry removing the import directive.",
  "code": "[object Object]",
  "severity": "Warning"
}

The message field is correctly populated. The code field is wrong.

Expected

{
  ...,
  "code": "unused_import",
  ...
}

Or, if code is genuinely the LSP rich form {value, target}, then either:

  • Pass through as { value: "unused_import", target: "https://dart.dev/diagnostics/unused_import" }, OR
  • Extract .value to a string before serialization.

Why this matters

The code field is what downstream code uses for case-dispatch / categorization. When it's the literal string "[object Object]":

  1. The model can't reliably reason about diagnostic categories (it sees the same code for everything, only the message differs).
  2. Any UI / bridge component that does switch (diagnostic.code) hits its default arm — and if that default arm throws, the failure surfaces as Unhandled case: [object Object] (#59013, #59047, #59067, etc.).
  3. The remote-control bridge (#59158) appears to be one such consumer that wedges when fed a stream of these malformed payloads.

Likely cause

VS Code's Diagnostic.code API has two valid shapes per the API docs:

code?: string | number | { value: string | number; target: Uri };

Many language servers (Dart Code included) use the rich {value, target} form so that diagnostics link to documentation. If the extension's diagnostic-serialization layer does:

const code = String(diagnostic.code);   // or `${diagnostic.code}` — same thing

…it produces "[object Object]" for the rich form, because plain JS objects have no custom toString().

The fix is a one-liner:

const code = typeof diagnostic.code === 'object' && diagnostic.code !== null
    ? String(diagnostic.code.value)
    : String(diagnostic.code ?? '');

Environment

  • VS Code on Windows 11 (build 26200)
  • Claude Code extension (latest stable as of 2026-05-14)
  • Dart Code extension active on a Flutter project
  • Reproduced consistently — every Edit to a Dart file in this session produced this output

Cross-references

  • #59158 — VS Code remote-control half-state. Combined with this bug, the malformed code payload appears to be what wedges the remote-control bridge serializer, causing the Unhandled case: [object Object] cascade.
  • #59013 / #59047 / #59067 — likely downstream symptoms (the Unhandled case banner is the user-visible artifact when the bridge serializer chokes on the malformed payload).

View original on GitHub ↗

This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗