You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Invalid JSON/C causes "Unexpected server error" on startup #29200
Any syntax error in opencode.jsonc (invalid JSONC, schema validation error) produces an unhelpful error message on startup:
Error: 4 of 6 requests failed: Unexpected server error. Check server logs for details.
Affected startup requests: config.providers, provider.list, app.agents, config.get
The actual error details (line/column of JSONC syntax errors, schema validation issues) are lost because ConfigParse.jsonc() throws JsonError and ConfigParse.effectSchema() throws InvalidError as plain exceptions, which become Effect defects and bubble up as a generic HTTP 500.
Plugins
none
OpenCode version
1.15.10
Steps to reproduce
Create opencode.jsonc with invalid JSONC syntax (e.g., missing quote, or brace)
Run opencode
Observe the generic error message instead of the actual parse/validation error location
The duplicate-bot and issue summary claim that PRs #29238 and #29208 are duplicates, both addressing issue #29200 ("Invalid JSON/C causes 'Unexpected server error' on startup").
The Reality
These are not duplicates. They address the same root issue at different architectural layers with different UX tradeoffs. Both are valid and complementary.
When config parse/schema validation fails, return empty {} config
Server starts
Server starts with defaults, allowing users to recover
Logging
Errors are logged to server logs for debugging
Scope
Main config loading path only
How it works
constdata=yield*Effect.sync(()=>{constparsed=ConfigParse.jsonc(expanded,source)constcleaned=stripUnknownKeys(normalizeLoadedConfig(parsed,source))constresult=ConfigParse.schema(Info,cleaned,source)parsedOk=truereturnresult}).pipe(Effect.catchCause((cause)=>Effect.sync(()=>{consterrors=cause.reasons.filter(Cause.isDieReason).map((r)=>(r.defectinstanceofError ? r.defect.name : "UnknownError")).join(", ")log.error("invalid config: config file could not be parsed",{path: source,error: errors})return{}asInfo}),),)
Value
Graceful startup: Server starts even with bad config
Zero blocking: Users can fix config later
Minimal changes: Single error boundary in config loading
Mirrors existing pattern: Same approach already used in tui.ts
Limitations
No client feedback: Clients don't know config is broken
Silent failures: Users might not realize config is invalid
Resolution: The old test verified security (don't expose sensitive config paths). The new test verifies UX (expose structured error). Both are valid concerns.
PR #29238's HTTP middleware fix provides zero value for CLI users. The CLI invokes config loading directly via Config.use.get() in the main entry point, which calls the same config.ts code path that #29208 hardens. Any config errors are caught at the source and logged — they never traverse the HTTP layer where #29238's middleware sits.
OpenCode desktop 500 "Unexpected server error" with ConfigJsonError
Summary
UI request fails with 500 and ref err_ad5ee91b.
Server logs show repeated ConfigJsonError during config load.
Background dependency install fails for @opencode-ai/plugin@local.
Environment
App: OpenCode 1.15.10 (packaged)
OS: Windows (win32, x64)
Electron: 41.2.1
Node: 24.14.1
Time: 2026-05-28 around 14:00 local
Steps to Reproduce
Launch OpenCode desktop.
Trigger a request that hits the backend (details unknown).
Expected
Requests succeed and the server starts without errors.
Actual
UI shows:
Error: Unexpected server error. Check server logs for details.
at wrapClientError (oc://renderer/assets/main-CqEM7zM6.js:63862:12)
at request (oc://renderer/assets/main-CqEM7zM6.js:60102:28)
at async retry (oc://renderer/assets/main-CqEM7zM6.js:64628:14)
at async Promise.all (index 0)
at async oc://renderer/assets/main-CqEM7zM6.js:66214:11
Reason:
{
"body": {
"name": "UnknownError",
"data": {
"message": "Unexpected server error. Check server logs for details.",
"ref": "err_ad5ee91b"
}
},
"status": 500
}
Server Logs (redacted paths)
WARN 2026-05-28T14:00:13 service=config dir=C:\Users\<redacted>\.config\opencode error=Cause([Fail(NpmInstallFailedError (cause: @opencode-ai/plugin: No matching version found for @opencode-ai/plugin@local.))]) background dependency install failed
ERROR 2026-05-28T14:00:14 service=server ref=err_ad5ee91b error=ConfigJsonError cause=ConfigJsonError: ConfigJsonError
Notes
Multiple ConfigJsonError entries appear during startup.
If needed, full logs are available in server-1/2026-05-28T140012.log and server-1/2026-05-28T140005.log.
Activity
github-actions commentedon May 25, 2026
This issue might be a duplicate of existing issues. Please check:
If you believe these are distinct issues, feel free to keep this open and link them for cross-reference.
HaleTom commentedon May 26, 2026
PR #29238 vs #29200: Disambiguation
The Assertion
The duplicate-bot and issue summary claim that PRs #29238 and #29208 are duplicates, both addressing issue #29200 ("Invalid JSON/C causes 'Unexpected server error' on startup").
The Reality
These are not duplicates. They address the same root issue at different architectural layers with different UX tradeoffs. Both are valid and complementary.
Issue #29200 (User Bug Report)
Any syntax error in
opencode.jsoncproduces an unhelpful error message:The actual error details (line/column of JSONC syntax errors, schema validation issues) are lost.
PR #29208: Defense in Depth at Source
Approach: Catch config errors at the config loading layer using
Effect.catchCauseinsideEffect.sync.Location:
packages/opencode/src/config/config.ts:420-456What it does
{}configHow it works
Value
tui.tsLimitations
PR #29238: Client-Facing Error Exposure
Approach: Map config errors to structured HTTP 400 responses at the HTTP middleware layer.
Location:
packages/opencode/src/server/routes/instance/httpapi/middleware/error.ts:22-25What it does
ConfigJsonError/ConfigInvalidErrorresponsesHow it works
Value
Limitations
Potential Conflicts
1. UX Philosophy Conflict
Resolution: These are complementary, not conflicting. Server startup should be graceful (#29208), but clients should be informed (#29238).
2. Test Expectation Conflict
The old test in
httpapi-error-middleware.test.tsasserted:PR #29238 changed this to:
Resolution: The old test verified security (don't expose sensitive config paths). The new test verifies UX (expose structured error). Both are valid concerns.
3. Layer Priority
If both PRs are applied:
This is actually a problem: PR #29238's value is diminished if PR #29208 catches everything.
Resolution needed: Either:
CLI Users
PR #29238's HTTP middleware fix provides zero value for CLI users. The CLI invokes config loading directly via
Config.use.get()in the main entry point, which calls the sameconfig.tscode path that #29208 hardens. Any config errors are caught at the source and logged — they never traverse the HTTP layer where #29238's middleware sits.CLI users benefit only from #29208:
HTTP clients benefit from both:
If the goal is CLI-only fixes, #29238 is unnecessary. If the goal is end-to-end UX, both are required.
Recommendation : Keep Both PRs (Current State)
Rationale:
When #29208 catches everything: #29238 becomes redundant.
When #29208 doesn't catch something: #29238 provides client feedback.
Verdict
Not duplicates. Both PRs address the same user-facing issue (#29200) but at different architectural layers:
Both bring value. Keep both unless #29208 proves to catch all config errors (in which case #29238 becomes redundant).
HaleTom commentedon May 26, 2026
@YOMXXX any ideas based on the above summary?
Note that
tui.jsonerror handling currently follows the same path that I'm implementing.imsquner commentedon May 28, 2026
OpenCode desktop 500 "Unexpected server error" with ConfigJsonError
Summary
Environment
Steps to Reproduce
Expected
Requests succeed and the server starts without errors.
Actual
UI shows:
Server Logs (redacted paths)
Notes
opencode-debug-20260528T140555.zip
github-actions commentedon Jul 28, 2026
To stay organized issues are automatically closed after 60 days of no activity. If the issue is still relevant please open a new one.