Skip to content

mcpx(diagnose): CallError blames a field the server never named — fieldInMessage substring-matches prop names inside unrelated words ('valid' in 'invalid' beats the named 'id') #1646

Closed

Description

@dezren39

Problem

diagnose.CallError maps a server's -32602 back to an argument by finding a declared property name inside the server's message — but fieldInMessage (pkgs/mcpx/internal/diagnose/diagnose.go:594-603, called from CallError at :545) uses a bare strings.Contains with a longest-name-wins rule and no word boundaries. Any prop name that happens to be a substring of an unrelated word in the message is treated as named by the server, and a longer accidental substring beats the field the server actually named.

Evidence (verified on main ed8e5910)

Probe test in the real internal/diagnose package (laptop worktree, file sha256 9d9c9207 identical in both clones; probe + log in the creator's run records, run twice with identical results). All calls: CallError with code -32602, Args: {}, no required arguments missing (so the fieldInMessage branch is the one that fires):

  • CTRL — props {id, query}, message invalid params: "query" must be a string → field=query ✅ (the field actually named)
  • CTRL — props {state, count}, message invalid params: schema mismatch → field="", generic diagnostic ✅
  • BUG-A — props {id, query}, message invalid params: validation failed (names no field) → field=id, diagnostic reads "the server rejected id (it wants string)" — id was found inside invalid / validation
  • BUG-B — props {name, limit}, message invalid params: unnamed argument rejected → field=name — found inside unnamed
  • BUG-C (worst) — props {id, valid}, message invalid params: "id" must be a string (names only id) → field=valid, "the server rejected valid (it wants boolean)" — valid is a substring of invalid and wins over the genuinely named id purely by being longer

The existing package tests pass unchanged; no existing test exercises a prop name that is a substring of a common error word.

Why it matters

This diagnostic is the daemon's explanation layer for failed calls (internal/daemon/callerr.go calls diagnose.CallError): it is quoted to the user as fact — which argument the server rejected, what type it wants, and (via Changed: cat.change(path, field)) which schema change supposedly explains it. A misattributed field sends the user to fix the wrong argument, attaches the wrong field's change history, and in BUG-C's shape actively overrides the one piece of information the server did provide. Short prop names (id, name, type, text, valid, limit…) are extremely common, and "invalid"/"validation" are the most common words in exactly the messages this branch handles.

Acceptance criteria

  • fieldInMessage (or its replacement) only attributes a field when the message names it as a token/word — substrings inside larger words (valid⊂invalid, id⊂validation, name⊂unnamed) never match
  • When the message names a field exactly, that field is returned even if a longer prop name appears as a substring of another word (BUG-C shape is a regression test)
  • When no field is named, CallError falls through to the generic diagnostic (field empty), as the CTRL generic case does today
  • Regression tests cover BUG-A/B/C shapes; existing internal/diagnose tests pass unchanged
  • Quoted names ("query") and common server phrasings (argument 'x', x is required) still match

Scope notes

Fix surface is the one function plus tests in pkgs/mcpx/internal/diagnose. Whether matching should also handle quoted/backticked spellings preferentially is for triage to pin; the word-boundary requirement is the defect. Not self-solved by the creator: the matching contract (which token shapes count as "named") is a small pin for queue-lane triage, and the creator run's remaining time could not also do the laptop worktree + PR + CI cycle responsibly.

Activity

  1. developing-today commented on Oct 28, 2026

    @developing-today
    Contributor
  2. added
    kind/bugSomething isn't working (prefixed form of the classic bug label)
    queue/queuedHas a queued task in the Supabase agent queue
    source/creatorFiled by the new-issue-creator job
    task/triageQueue packet kind: verify, reproduce, and route this item
    priority/normalOrdinary priority (the default)
    app/mcpxPackage/app: mcpx (pkgs/ or apps/ in this repo)
    effort/sSmall: expected under 2 hours of work
    on Oct 28, 2026
  3. dezren39 commented on Oct 28, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · filed

    • Agent: new-issue-creator job (lane B, new-issue-creator-code-b)
    • Session / ID: cron new-issue-creator-code-b run 2026-10-28 05:20 CDT
    • Found via: filed this run
    • Task: Triage the fieldInMessage substring misattribution in mcpx internal/diagnose (CallError blames a field the server never named; a longer accidental substring beats the field actually named)
    • Expectation: effort/s — done when field attribution requires a word/token match, BUG-A/B/C regression tests exist, and existing diagnose tests pass
    • Links: packet packet-1646.json (repo-health-code-pilot, triage)
  4. added
    work/assignedQueue worker lifecycle state
    queue/claimedQueue worker lifecycle state
    and removed
    queue/queuedHas a queued task in the Supabase agent queue
    on Oct 31, 2026
  5. 25 remaining items

  6. dezren39 commented on Oct 31, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · parked

  7. dezren39 commented on Oct 31, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · parked

  8. added
    queue/claimedQueue worker lifecycle state
    and removed
    status/parkedDeliberately paused with a recorded resume condition
    queue/parkedQueue task is parked (waiting on CI, time, or an event)
    on Oct 31, 2026
  9. dezren39 commented on Oct 31, 2026

    @dezren39
    MemberAuthor

    Fixed by PR #3041 (squash-merged 60f68d2): fieldInMessage token-boundary matching with quote preference, plus the Codex-P2 empty-property-name guard and regression tests. CI on head 7ee0e0d was fully green (lint, plugin tests, stress PR-changed, docs, final CI budget) and Codex review completed with no unresolved findings. Queue task 4083 completed fixed_merged.

  10. dezren39 commented on Oct 31, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · done

    • Agent: queue worker (repo-worker-code), lane A shift
    • Session / ID: queue task 4083, shift 2026-10-31 07:44 CDT
    • Found via: queue claim (resume of PR 3041)
    • Task: merged PR 3041 (squash, 60f68d2) after fresh verification: all CI green on 7ee0e0d and the Codex gate cleared earlier this shift (P2 fixed in head, thread resolved, re-review clean). Issue closed manually — the PR had no auto-close linkage. Task 4083 completed fixed_merged.
    • Expectation: done — diagnose fieldInMessage token-boundary matching is on main
    • Links: PR fix(mcpx): fieldInMessage token-boundary matching with quote preference (#1646) #3041
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

app/mcpxPackage/app: mcpx (pkgs/ or apps/ in this repo)effort/sSmall: expected under 2 hours of workkind/bugSomething isn't working (prefixed form of the classic bug label)priority/normalOrdinary priority (the default)source/creatorFiled by the new-issue-creator jobtask/triageQueue packet kind: verify, reproduce, and route this item

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions