Repository navigation
Conversation
JSON.parse throwing inside Effect.fn becomes an Effect defect that bypasses Effect.orElseSucceed and similar typed-error recovery patterns. Wrap parse in Effect.try returning a FileSystemError so callers can recover from corrupted JSON files (e.g. half-written auth.json on interrupted writes). Part of fix for #27530.
Add Effect.logWarning before falling back to empty credentials so users see why their auth file was ignored (the original symptom is the cryptic '4 of 5 requests failed' with no log file). Apply the same recovery path to OPENCODE_AUTH_CONTENT, and run both branches through Record.filterMap so they share the same Record<string, Info> shape.
Five new it.live tests verifying Auth.all/get/set survive: half-written JSON, binary garbage, single-key lookup on corrupted file, set() recovery after corruption, and invalid OPENCODE_AUTH_CONTENT.
Previous web-upload introduced CRLF line endings on every line, making the diff appear as a full-file rewrite. Reupload the same content with LF line endings so the actual change (the Effect.try wrap on JSON.parse) is the only diff.
Per PR review: previous tapError fired Effect.logWarning for any readJson error including the normal first-run case where auth.json doesn't exist yet. Narrow the warning to FileSystemError (which is now produced by the JSON.parse wrap) so missing-file is silent and only actual corruption is logged. Also LF line-ending fix.
Replace the negative bad-OPENCODE_AUTH_CONTENT test (which would have passed even on the old code: bad env -> catch swallows -> fall through -> missing-file orElseSucceed -> {}) with a positive test verifying valid env content is honored end-to-end. Also LF line-ending fix on the whole test file.
|
Thanks for your contribution! This PR doesn't have a linked issue. All PRs must reference an existing issue. Please:
See CONTRIBUTING.md for details. |
|
Issue #27530 |
|
Friendly nudge — rebased on latest |
|
This PR also fixes #18351 ("readJson() lacks error handling for malformed JSON"), which is currently open with no associated PR. The change to It also resolves a separate crash path: Consider adding |
|
Thanks @edevil — really appreciate the cross-link. Updating the PR description to add |
|
I was looking into this issue and noticed that the fix still seems relevant, but the current dev branch has changed since this PR was opened. It looks like readJson / writeJson moved from Would it make sense to rebase this against the current dev layout, or would maintainers prefer a fresh follow-up PR? |
|
Automated PR Cleanup Thank you for contributing to opencode. Due to the high volume of PRs from users and AI agents, we periodically close older PRs using automated criteria so maintainers can focus review time on the most active and community-supported contributions. This PR was closed because it matched the following cleanup criteria:
PRs created within the last month are not affected by this cleanup. If you believe this PR was closed incorrectly, or if you are still actively working on it, please leave a comment explaining why it should be reopened. A maintainer can review and reopen it if appropriate. Thanks again for taking the time to contribute. |
Closes #29628, #18351
Issue for this PR
Refs #27530 (sub-cause: corrupted
auth.jsonfrom interrupted writes — the issue thread also tracks provider-API 5xx,#-in-instructions parser crash, and SSL/config failures, all of which are out of scope here)Type of change
What does this PR do?
When
auth.jsonis left in a corrupt state (whitespace-only or otherwise unparseable — typically because a process was killed mid-write), opencode currently crashes at startup with the cryptic:No log file is created (the failure happens before logging is wired). The community workaround on issue #27530 is to nuke
~/.local/share/opencode/(or its Windows equivalent) — destroying every saved session. 10+ users have hit this across Windows, NixOS, Pop!_OS, macOS, and WSL.Root cause:
FileSystem.readJsoninpackages/core/src/filesystem.tscalledJSON.parsesynchronously inside anEffect.fngenerator. ASyntaxErrorfromJSON.parsebecomes an Effect defect, not a typed failure.Auth.allthen wrapped the call withEffect.orElseSucceedwhich only catches typed failures — the defect bypassed it and crashed the fiber. Every config-dependent request (Config.loadInstanceState→Auth.all→readJson) failed with the generic "Unexpected server error".Changes
packages/core/src/filesystem.ts— wrapJSON.parseinEffect.tryreturning a typedFileSystemError, matching the existing pattern at line 81 (readDirectoryEntries).Effect.orElseSucceed/Effect.tapErrorin callers can now actually intercept parse failures.packages/opencode/src/auth/index.ts— log a warning only onFileSystemError(parse failure) so first-run users with noauth.jsonstay silent and only actual corruption is surfaced. Apply the same recovery + log to theOPENCODE_AUTH_CONTENTenv-var branch and run it throughRecord.filterMapso both branches return the sameRecord<string, Info>shape.packages/opencode/test/auth/auth.test.ts— 5 newit.livetests covering: half-written JSON, binary garbage, single-keyget()lookup on corrupted file,set()recovery after corruption, and positive verification that validOPENCODE_AUTH_CONTENTis honored end-to-end.Out of scope (intentional, to keep this PR small):
writeJsonto prevent future corruption — being addressed independently in fix(storage): write json files atomically #28010.#character in instructions file crashing the parser (sub-cause [c]) — separate bug.How did you verify your code works?
bun typecheckfrompackages/core— clean (tsgo exit 0)bun typecheckfrompackages/opencode— cleanbun test test/filesystem/frompackages/core— 26/26 pass (no regressions)bun test test/auth/ test/filesystem/frompackages/opencode— 33/33 pass (was 28; +5 new tests)auth.jsonwith 300 spaces — before: crash with "4 of 5 requests failed"; after: opencode starts, logsfailed to parse auth file at <path>, treating as empty; run 'opencode auth login' to recover (...)and continues.Screenshots / recordings
Not a UI change.
Checklist