Skip to content

🤖 fix: show the field and rule for oRPC input validation errors - #7826

Merged
ThomasK33 merged 5 commits into
mainfrom
fix/backup-validation-message
Oct 31, 2026
Merged

ThomasK33 merged 5 commits into
mainfrom
fix/backup-validation-message

Conversation

@ThomasK33

Copy link
Copy Markdown
Member

Why

Fixes #7771. When a settings form sends input that the oRPC schema rejects, the app shows only "Input validation failed", so the user cannot tell which field is wrong. In Settings > Backup, an invalid branch or subdirectory hit this.

What changed

  • getErrorMessage now appends each schema issue from the oRPC error's data.issues as <field>: <rule>. Example: Input validation failed: branch: Enter a valid Git branch name.
  • The issue-path formatter moved from the server log formatter to a shared module, so the client and server logs use one copy.

Scope

  • This covers every caller of getErrorMessage, not only Backup.
  • The field shows as its schema key. The Backup subdirectory field shows as path, and the rule text names it.

Blast Radius

Only errors that carry data.issues change, so other error messages stay the same. The existing message clamp still limits length.

Verification

  • A Backup UI test sends the save through the real backup.saveSettings schema. It failed with only the generic message and now shows the field and rule. Its expected text comes from the schema.
  • The sub-agent checked the message in the real UI with a sandbox dev server at desktop width and at 390px.

Generated with xum • Model: anthropic:claude-opus-5-5 • Thinking: high • Cost: $13.47

Saving an invalid branch or subdirectory runs the real backup.saveSettings
input validation, then expects the shown error to name the field and the
schema's rule. It fails today: the section shows only
"Input validation failed".

---

_Generated with `xum` • Model: `anthropic:claude-opus-5-5` • Thinking: `high` • Cost: `$`_

<!-- mux-attribution: model=anthropic:claude-opus-5-5 thinking=high costs= -->
oRPC rejects schema-invalid input with "Input validation failed" and puts
each schema issue in data.issues, which reaches the client. getErrorMessage
read only error.message, so every form that showed it lost the field and
rule. It now appends each issue as "<path>: <message>".

The issue-path formatter moves from the server's formatOrpcError to
src/common/utils/errors/formatValidationIssues.ts so both share it.

---

_Generated with `xum` • Model: `anthropic:claude-opus-5-5` • Thinking: `high`_

<!-- mux-attribution: model=anthropic:claude-opus-5-5 thinking=high -->
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 31, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-31T09:25:45.053973Z a58e0bc Manual request
🔒 Security Review ✅ Completed 2026-10-31T09:26:21.386727Z a58e0bc Manual request
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@ThomasK33

Copy link
Copy Markdown
Member Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

🛡️ Codex Security Review · Automatically triggered

Security review completed. No security issues were found in this pull request.

Reviewed commit: dadb32fc20

View security finding report

Only the user who started this review can view the report in Codex.

ℹ️ About Codex security reviews in GitHub

This is an experimental Codex feature. Security reviews are triggered when:

  • You comment "@codex security review"
  • A regular code review gets triggered (for example, "@codex review" or when a PR is opened), and you’re opted in so security review runs alongside code review

Once complete, Codex will leave suggestions, or a comment if no findings are found.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: dadb32fc20

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@github-actions

github-actions Bot commented Oct 31, 2026 •

Copy link
Copy Markdown
Contributor

🟢 e2e stories (Haiku): 14 passed

22 agent steps · 7 replayed from cache · 15 model calls · 46.2k tokens (28% cached)
Spend: $0.08 of the $1.00 cap (proxy ledger)

All 14 tests in 9 files
Test Agent Time
🟢 chatRestart.e2e.ts · 1 passed 1 step · 1 call 5.0s
🟢 a chat survives a restart of the server 1 step · 1 call 5.0s
🟢 compaction.e2e.ts · 1 passed 1 step · 1 call 7.8s
🟢 /compact replaces the old chat with a summary 1 step · 1 call 7.8s
🟢 pluginTrustRestart.e2e.ts · 1 passed 4 steps · 2 calls 12.1s
🟢 a trusted plugin hook stays trusted after the server restarts 4 steps · 2 calls 12.1s
🟢 settingsRoundTrip.e2e.ts · 1 passed 2 steps · 1 call 11.4s
🟢 a chat survives trips through Settings 2 steps · 1 call 11.4s
🟢 sidebarPerWorkspace.e2e.ts · 1 passed 4 steps · 1 call 4.6s
🟢 a new workspace starts with its right sidebar collapsed while another keeps it open 4 steps · 1 call 4.6s
🟢 smoke.e2e.ts · 1 passed 2 steps · 1 call 2.4s
🟢 the agent opens the playground workspace 2 steps · 1 call 2.4s
🟢 streamErrors.e2e.ts · 1 passed 1 step · 1 call 6.5s
🟢 stream errors show in the chat, and the chat recovers 1 step · 1 call 6.5s
🟢 todoNudge.e2e.ts · 1 passed 1 step · 1 call 3.4s
🟢 the agent finishes open TODO items after the turn-end nudge 1 step · 1 call 3.4s
🟢 touchAlignment.e2e.ts · 6 passed 6 steps · 6 calls 24.6s
🟢 the Settings close button is level with the title on a touch screen 390px wide 1 step · 1 call 3.2s
🟢 the Settings close button is level with the title on a touch screen 768px wide 1 step · 1 call 3.7s
🟢 Backup settings checkboxes are small and level with their labels on a touch phone 1 step · 1 call 4.9s
🟢 the heartbeat checkbox is small and level with its label on a touch phone 1 step · 1 call 3.4s
🟢 a reply's model and time stay on one line on a touch phone 1 step · 1 call 6.5s
🟢 the workspace actions menu stays on the title row on a touch phone 1 step · 1 call 2.8s

e2e 0.20.0 · 1m 21s · web · run artifacts

🟢 e2e Electron stories (Haiku): 3 passed

3 agent steps · 3 model calls · 8.0k tokens (32% cached)
Spend: $0.01 of the $1.00 cap (proxy ledger)

All 3 tests in 3 files
Test Agent Time
🟢 electron/deepLink.e2e.ts · 1 passed 1 step · 1 call 5.5s
🟢 a deep link of a second launch starts a chat in the running app 1 step · 1 call 5.5s
🟢 electron/menuBar.e2e.ts · 1 passed 1 step · 1 call 6.2s
🟢 the workspace menu bar is the desktop title bar 1 step · 1 call 6.2s
🟢 electron/smoke.e2e.ts · 1 passed 1 step · 1 call 5.1s
🟢 Xum Electron opens the playground workspace 1 step · 1 call 5.1s

e2e 0.20.0 · 19.0s · electron · run artifacts

🟢 e2e agent repros (Haiku): no tests selected

Spend: $0.00 of the $1.00 cap (proxy ledger)

e2e 0.20.0 · 5.4s · 2 targets (web, phone) · run artifacts

@ThomasK33

Copy link
Copy Markdown
Member Author

Independent UI verification: PASS+NOTES at dadb32f

I did not write this code. I compared main and this PR in two isolated dev servers. Each server had its own temp XUM_ROOT and free ports (make dev-server-sandbox --clean-providers --clean-projects). I drove both with agent-browser.

Steps

  1. I ran git fetch origin and made two detached worktrees. Parent was origin/main at 85abd10b10, which is the merge base. Head was dadb32fc20. The head app's version label reads v0.32.2-nightly.91-3-gdadb32fc20.
  2. In Settings > Backup I set Repository URL to https://github.com/example/backup.git. Then I clicked Save settings with each invalid input below and read the red p.text-error text.
  3. For a second check I called the save routes of two other settings forms through the app's own window.__ORPC_CLIENT__: Agent resource limits (agentResourceLimits.set) and Experiments > API server (server.setApiServerSettings). I also called one route that rejects a nested array input (providers.setModels). Each error went through the build's own getErrorMessage, which I imported from Vite.
  4. I took screenshots of the head errors at 1440x900 and 390x844.

Settings > Backup, parent vs head

Input Parent (main) Head (this PR)
Branch no such branch! Input validation failed Input validation failed: branch: Enter a valid Git branch name
Subdirectory ../escape Input validation failed Input validation failed: path: Enter a subdirectory inside the repository
URL https://user:tok@github.com/... Input validation failed Input validation failed: repoUrl: Remove the credential embedded in the repository URL
Bad branch and ../escape together Input validation failed Input validation failed: branch: Enter a valid Git branch name; path: Enter a subdirectory inside the repository

Other settings routes (real oRPC wire errors through getErrorMessage)

Call Parent Head
agentResourceLimits.set({cpuCores: 0, memoryGiB: 99999}) Input validation failed Input validation failed: cpuCores: Too small: expected number to be >=0.1; memoryGiB: Too big: expected number to be <=16384
server.setApiServerSettings({bindHost: null, port: 70000}) Input validation failed Input validation failed: port: Too big: expected number to be <=65535
providers.setModels({provider: "openai", models: [42]}) Input validation failed Input validation failed: models[0]: Invalid input

None of the messages were garbled. Each one used the <field>: <rule> shape the PR describes, joined with ; , and the array index rendered as models[0].

Notes

  1. I found no other settings form that sends a zod-invalid value from its UI. Agent resource limits, the API server port, task limits and heartbeat intervals all check or clamp the value in the client first. MCP and Secrets show err.message instead of getErrorMessage. A haiku explore pass agreed. So in the UI the change is visible only on the Backup form today. The other routes in the table above prove the formatting on real wire errors, but no user reaches them from those forms.
  2. At 390px the long message wraps inside the card with no overflow (screenshots below).
  3. The message keeps the zod field key (repoUrl, path), not the UI label ("Repository URL", "Subdirectory"). It is readable, but path for the Subdirectory field is a small mismatch. This is a possible follow-up, not a blocker.
  4. bun test src/common/utils/errors.test.ts src/common/utils/errors/formatValidationIssues.test.ts on head passed 25 tests with 0 failures. I did not test a thrown non-validation ORPCError in the UI. The unit test "keeps the message of an oRPC error whose data has no issues" covers that case.

Head, desktop, invalid branch
Head, desktop, invalid subdirectory
Head, 390px, invalid branch
Head, 390px, invalid subdirectory


Generated with xum • Model: anthropic:claude-opus-5-5 • Thinking: high • Cost: $1.91

@ThomasK33

Copy link
Copy Markdown
Member Author

@codex review

Please take another look. Both findings are fixed in 9815ff5.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 9815ff5e11

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@chatgpt-codex-connector

Copy link
Copy Markdown

🛡️ Codex Security Review · Automatically triggered

Security review completed. No security issues were found in this pull request.

Reviewed commit: 9815ff5e11

View security finding report

Only the user who started this review can view the report in Codex.

ℹ️ About Codex security reviews in GitHub

This is an experimental Codex feature. Security reviews are triggered when:

  • You comment "@codex security review"
  • A regular code review gets triggered (for example, "@codex review" or when a PR is opened), and you’re opted in so security review runs alongside code review

Once complete, Codex will leave suggestions, or a comment if no findings are found.

@ThomasK33

Copy link
Copy Markdown
Member Author

@codex review

Please take another look. The limits moved to src/constants/errors.ts.

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. 🚀

Reviewed commit: a58e0bc2d6

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@chatgpt-codex-connector

Copy link
Copy Markdown

🛡️ Codex Security Review · Automatically triggered

Security review completed. No security issues were found in this pull request.

Reviewed commit: a58e0bc2d6

View security finding report

Only the user who started this review can view the report in Codex.

ℹ️ About Codex security reviews in GitHub

This is an experimental Codex feature. Security reviews are triggered when:

  • You comment "@codex security review"
  • A regular code review gets triggered (for example, "@codex review" or when a PR is opened), and you’re opted in so security review runs alongside code review

Once complete, Codex will leave suggestions, or a comment if no findings are found.

@ThomasK33
ThomasK33 added this pull request to the merge queue Oct 31, 2026
Merged via the queue into main with commit 4d4be70 Oct 31, 2026
33 of 34 checks passed
@ThomasK33
ThomasK33 deleted the fix/backup-validation-message branch October 31, 2026 10:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

🤖 Backup settings: invalid branch or subdirectory shows only "Input validation failed"

1 participant