Skip to content

🤖 fix: report an unreadable config.json instead of null getInfo and corrupt-file errors - #5777

Merged
ThomasK33 merged 3 commits into
mainfrom
fix/config-unreadable-getinfo
Oct 6, 2026
Merged

ThomasK33 merged 3 commits into
mainfrom
fix/config-unreadable-getinfo

Conversation

@ThomasK33

@ThomasK33 ThomasK33 commented Oct 6, 2026 •

Copy link
Copy Markdown
Member

Summary

When config.json cannot be read or parsed, the backend now reports that cause. workspace.getInfo rejects with the load error instead of returning null. An edit refused after an unreadable read says the file could not be read and no longer tells the user to move a corrupt file aside. Later edits, sends and stream resumes give the same cause instead of "Workspace not found". When the file is readable again, the next getInfo and edit succeed and the load error clears, with no restart.

Fixes #5757

Background

A failed load returns the defaults view, which has no workspaces. So every lookup missed, and callers reported "not found" (or null) for workspaces that are still registered on disk. The edit gate also had one message for every failed load, and that message was written for a corrupt file.

Implementation

  1. Config records two in-memory fields in the existing process-scoped load-failure map: unreadable (no bytes were read) and errorMessage. Nothing new is persisted.
  2. The new Config.getConfigLoadError() returns a message for the last failed load, or null. It is a map lookup with no I/O. It reports a failure only when this Config instance's own last load wrote it. The map is shared by path, and short-lived instances (for example in runtimeFactory) must not make a healthy instance report their failure. handleConfigLoadFailure stores the state object it wrote in a new private field, observedLoadFailure, and getConfigLoadError() reports the map entry only when it is that same object. That check is one identity compare: still no fs call, stat or loadConfigOrDefault. readConfigOrDefault and the snapshot clear/keep rules from 🤖 perf: keep the config snapshot while it still matches the file #5750 are unchanged, and snapshot.test.ts is unchanged and passes. For a parse failure without a confirmed .corrupt- backup, the message does not point to a backup.
  3. assertConfigWritable refuses an unreadable file with "config.json could not be read ()...". The corrupt-file text stays for parse failures.
  4. The workspace.getInfo route handler calls the unchanged WorkspaceService.getInfo. When that returns null and getConfigLoadError() is set, the handler throws ORPCError("SERVICE_UNAVAILABLE") with the load error. The route does this check itself, so the PR adds no new WorkspaceService method. getInfo keeps returning null for internal callers.
  5. In WorkspaceService, the 26 Err("Workspace not found") returns become Err(this.workspaceNotFoundError()). The private helper returns the load error when one is set, else "Workspace not found". Each site is a one-line change. The two "Workspace not found. It may have been deleted." guards in sendMessage and resumeStream prefer the load error the same way.

No change to the config snapshot, loadConfigOrDefault, buildWorkspaceMetadata, getWorkspaceMetadataById, workspaceIndex or latestUserText.

Callers of workspace.getInfo and what they do with a rejection

Caller Handling
WorkspaceContext.getWorkspaceInfo Exposed on the context, but nothing in src/browser calls it.
chatCommands.forkWorkspace Its callers (ProjectSidebar, WorkspaceMenuBar, AssistantMessage, the /fork command) wrap it in try/catch and show the message in the fork error popover or a toast.
chatCommands.createNewWorkspace Only the /new command calls it, inside try/catch, and shows a toast.
/new command (handleNewCommand) try/catch, shows the message in a toast.
/plan open command try/catch, shows the message in a toast.
ACP (acp/agent.ts, configOptions.ts, sessionFork.ts, sessionResume.ts) Most of these already threw "not found" on null. Now they throw the real cause. ACP /compact used ?. on the result, so it now fails with the load error instead of running with default settings.

No renderer change is needed: no caller crashes, and none shows "workspace removed".

Follow-up

Validation

  1. New tests fail on main and pass here. They run as a non-root user, because root ignores chmod 000:
    • workspaceService.configLoadError.test.ts calls the real workspace.getInfo route through createRouterClient and updateTitle on a real WorkspaceService with config.json at chmod 000. On main, getInfo returned null and both edits returned "Workspace not found". The test then restores the mode and checks that getInfo, the next edit and getConfigLoadError() recover.
    • The same test checks that sendMessage and resumeStream report the load error.
    • config.test.ts: with a warm snapshot, an edit to an unreadable file was refused with "the existing corrupt config has no confirmed backup yet". A parse failure is reported as "could not be parsed", and without a confirmed backup the message does not mention one. A second Config whose read fails does not change what the warm instance reports.
  2. Mutation check: I reverted each fix (route check, helper, unreadable branch, send/resume guards, instance check, backup wording) one at a time. Each revert made its test fail.
  3. src/node/config (including snapshot.test.ts), src/node/orpc and all workspaceService*.test.ts pass.

Risks

Low. The changes only touch paths where the config load already failed. In the normal case, getConfigLoadError() returns null and every message and return value stays the same.


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

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 6, 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-06T19:18:19.380711Z d603446 Manual request
🔒 Security Review ✅ Completed 2026-10-06T19:19:22.268184Z d603446 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.

@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: 877a25e3ff

ℹ️ 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".

Comment thread src/node/config/index.ts Outdated
Comment thread src/node/services/workspaceService.ts
Comment thread src/node/orpc/router.ts
Comment thread src/node/config/index.ts Outdated

@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: d603446106

ℹ️ 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".

Comment thread src/node/config/index.ts
@ThomasK33

Copy link
Copy Markdown
Member Author

@codex review

Final round on the unchanged head. Round 1 had 4 findings (3 fixed, 1 deferred to #5781). Round 2 had 1 finding, deferred to #5787 because it existed before this PR. An independent final check recommends ready with tracked follow-ups.

@chatgpt-codex-connector

Copy link
Copy Markdown

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

Reviewed commit: d603446106

ℹ️ 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: d603446106

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

Readiness record for head d603446106:

  1. Review rounds: round 1 (normal + security) had 4 findings: 3 fixed, 1 deferred to 🤖 fix: an unreadable config.json shows an empty workspace list with no error #5781. Round 2 (normal + security) had 1 finding, deferred to 🤖 fix: another Config's load failure can block edits after the file is readable again #5787 because it existed before this PR. The final normal review on this head found no major issues. An automatic security review also ran on this head and found no security issues.
  2. Assessments: 7, counting the final independent check. Findings went 4 → 1 → 0, strictly shrinking, and the 7th assessment was an automatic security run, so the standing +2 extension applies.
  3. Final independent check (clean context, assessment 5): ready with tracked follow-ups.
  4. CI: all required checks pass on this head. All review threads are resolved.
  5. Follow-ups: 🤖 fix: an unreadable config.json shows an empty workspace list with no error #5781 (empty workspace list after a failed load), 🤖 fix: another Config's load failure can block edits after the file is readable again #5787 (shared failure state in the edit check before each save).

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

@ThomasK33
ThomasK33 added this pull request to the merge queue Oct 6, 2026
Merged via the queue into main with commit b4b68f2 Oct 6, 2026
70 of 72 checks passed
@ThomasK33
ThomasK33 deleted the fix/config-unreadable-getinfo branch October 6, 2026 19:56
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.

🤖 fix: unreadable config.json gives null getInfo and misleading edit errors

1 participant