Skip to content

fix(opencode): report invalid agent/mode configs instead of crashing or dropping them#29784

Open
EClinick wants to merge 1 commit into
anomalyco:devfrom
EClinick:fix/config-agent-mode-error-handling
Open

fix(opencode): report invalid agent/mode configs instead of crashing or dropping them#29784
EClinick wants to merge 1 commit into
anomalyco:devfrom
EClinick:fix/config-agent-mode-error-handling

Conversation

@EClinick

Copy link
Copy Markdown

Issue for this PR

Closes #27133

Type of change

  • Bug fix
  • New feature
  • Refactor / code improvement
  • Documentation

What does this PR do?

packages/opencode/src/config/agent.ts had two near-identical loaders that handled invalid files differently. load() called ConfigParse.schema() which throws, so one bad agent file aborted the whole load and startup failed with ConfigInvalidError. loadMode() used Schema.decodeUnknownExit with an if (Exit.isSuccess) and no else, so a bad mode silently disappeared with no error.

Now both decode the same way and on failure they log, publish a Session.Event.Error, and skip just the bad file while continuing to load the rest. The shared log + publish logic moved into a small report() helper to avoid duplicating it across both functions.

How did you verify your code works?

Screenshots / recordings

N/A — not a UI change.

Checklist

  • I have tested my changes locally
  • I have not included unrelated changes in this PR

…or dropping them

An invalid file in agent/ threw ConfigInvalidError and aborted the whole
load (no agents loaded); the same file in mode/ was silently dropped with
no error. Both loaders now log, publish a session error, and skip just the
bad file while loading the rest.

Fixes anomalyco#27133
Copilot AI review requested due to automatic review settings May 28, 2026 18:57
@github-actions

Copy link
Copy Markdown
Contributor

The following comment was made by an LLM, it may be inaccurate:

I found a potentially related PR:

#29208: fix(config): catch parse errors gracefully during startup

This PR appears to address a similar issue — handling parse errors gracefully during startup. It may be related to your PR's goal of reporting invalid agent/mode configs instead of crashing. You should verify whether this PR already addresses the issue or if there's overlap in the fixes.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

Improves config loading resilience by reporting invalid agent/mode markdown files as user-visible errors while continuing to load valid configs.

Changes:

  • Added event-based error reporting for agent/mode config parsing failures.
  • Updated agent/mode loaders to skip invalid entries instead of crashing or silently dropping them.
  • Added tests to ensure invalid files are reported and don’t block valid files.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.

File Description
packages/opencode/src/config/agent.ts Adds a report() helper and updates agent/mode loaders to emit error events on parse failures.
packages/opencode/test/config/config.test.ts Adds tests and a helper to subscribe to error events and assert invalid configs are reported.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +89 to +100
function subscribeErrors(pattern: string, timeoutMs = 500) {
const errors: string[] = []
const matched = Promise.withResolvers<void>()
Bus.subscribe(Session.Event.Error, (evt) => {
const data = evt.properties.error?.data
if (!data || !("message" in data) || typeof data.message !== "string") return
errors.push(data.message)
if (data.message.includes(pattern)) matched.resolve()
})
const wait = Promise.race([matched.promise, Bun.sleep(timeoutMs)])
return { errors, wait }
}
errors.push(data.message)
if (data.message.includes(pattern)) matched.resolve()
})
const wait = Promise.race([matched.promise, Bun.sleep(timeoutMs)])
Comment on lines +139 to +143
const parsed = Schema.decodeUnknownExit(Info)(config, { errors: "all", propertyOrder: "original" })
if (Exit.isFailure(parsed)) {
await report("agent", item, `Failed to parse agent ${item}`, parsed.cause)
continue
}
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.

[BUG]: Invalid agent/mode config files: agent crashes startup, mode silently disappears

2 participants