Skip to content

Personal copy of anomalyco/opencode#29208: fix(config): catch parse errors gracefully during startup#4

Open
HaleTom wants to merge 66 commits into
devfrom
json-errors
Open

Personal copy of anomalyco/opencode#29208: fix(config): catch parse errors gracefully during startup#4
HaleTom wants to merge 66 commits into
devfrom
json-errors

Conversation

@HaleTom
Copy link
Copy Markdown
Owner

@HaleTom HaleTom commented May 25, 2026

Personal copy of anomalyco/opencode#29208

HaleTom added 4 commits May 25, 2026 18:41
Wrap ConfigParse.jsonc() and ConfigParse.effectSchema() calls in
loadConfig with Effect.catchCause to prevent sync-thrown JsonError
and InvalidError from becoming Effect defects. On parse/schema
failure, the bad file is skipped with a log.error and {} fallback
instead of crashing, matching the existing tui.jsonc error handling
pattern in tui.ts.

Without this, any invalid JSONC syntax or schema violation in
opencode.json/opencode.jsonc causes "4 of 6 requests failed:
Unexpected server error" on startup. Now the server starts with
default values and logs the config error details.

Fixes anomalyco#29200
Copilot AI review requested due to automatic review settings May 25, 2026 16:02
@semanticdiff-com
Copy link
Copy Markdown

semanticdiff-com Bot commented May 25, 2026

Review changes with  SemanticDiff

Changed Files
File Status
  packages/app/src/i18n/uk.ts  95% smaller
  packages/opencode/src/config/provider.ts  87% smaller
  packages/app/src/app.tsx  85% smaller
  packages/console/app/src/routes/zen/util/handler.ts  75% smaller
  packages/app/e2e/utils/mock-server.ts  72% smaller
  packages/app/src/pages/session.tsx  72% smaller
  packages/opencode/src/effect/runtime-flags.ts  70% smaller
  packages/opencode/test/cli/run/entry.body.test.ts  61% smaller
  packages/opencode/src/server/routes/instance/httpapi/groups/session.ts  57% smaller
  packages/app/src/pages/session/use-session-commands.tsx  53% smaller
  packages/app/src/pages/session/session-side-panel.tsx  53% smaller
  packages/opencode/src/tool/task.ts  46% smaller
  packages/app/src/components/prompt-input.tsx  42% smaller
  packages/opencode/src/acp-next/directory.ts  30% smaller
  packages/opencode/src/config/managed.ts  26% smaller
  packages/console/function/src/log-processor.ts  24% smaller
  packages/opencode/src/config/config.ts  20% smaller
  packages/opencode/src/server/routes/instance/httpapi/handlers/experimental.ts  20% smaller
  packages/app/src/pages/home.tsx  19% smaller
  packages/app/e2e/regression/session-timeline-context-resize.spec.ts  14% smaller
  infra/console.ts  14% smaller
  packages/opencode/test/tool/task.test.ts  13% smaller
  packages/opencode/test/cli/acp-next/acp-next-process.test.ts  12% smaller
  packages/app/e2e/regression/session-timeline-collapse-state.spec.ts  12% smaller
  packages/app/src/context/server.tsx  11% smaller
  packages/app/src/components/session/session-new-design-view.tsx  10% smaller
  packages/app/src/components/titlebar.tsx  10% smaller
  packages/opencode/test/config/config.test.ts  8% smaller
  packages/opencode/src/acp-next/usage.ts  7% smaller
  package.json  6% smaller
  packages/app/src/components/status-popover.tsx  6% smaller
  packages/opencode/src/server/routes/instance/httpapi/groups/global.ts  5% smaller
  infra/app.ts  4% smaller
  packages/opencode/test/tool/registry.test.ts  4% smaller
  packages/opencode/src/server/routes/instance/httpapi/groups/experimental.ts  3% smaller
  packages/app/src/components/status-popover-body.tsx  2% smaller
  packages/opencode/src/acp-next/service.ts  1% smaller
  packages/opencode/src/tool/registry.ts  1% smaller
  packages/app/src/utils/server-health.ts  1% smaller
  packages/opencode/src/acp-next/tool.ts  1% smaller
  .dockerignore Unsupported file format
  .github/workflows/deploy.yml  0% smaller
  bun.lock Unsupported file format
  infra/lake.ts  0% smaller
  infra/secret.ts  0% smaller
  infra/stage.ts  0% smaller
  infra/stats.ts  0% smaller
  nix/hashes.json  0% smaller
  packages/app/public/assets/Inter.ttf Unsupported file format
  packages/app/src/components/session/session-header.tsx  0% smaller
  packages/app/src/components/settings-general.tsx  0% smaller
  packages/app/src/context/servers.tsx  0% smaller
  packages/app/src/context/settings.tsx  0% smaller
  packages/app/src/i18n/en.ts  0% smaller
  packages/app/src/index.css Unsupported file format
  packages/app/src/pages/session/composer/session-composer-region.tsx  0% smaller
  packages/console/app/src/routes/zen/util/provider/anthropic.ts  0% smaller
  packages/console/app/src/routes/zen/util/provider/google.ts  0% smaller
  packages/console/app/src/routes/zen/util/provider/openai-compatible.ts  0% smaller
  packages/console/app/src/routes/zen/util/provider/openai.ts  0% smaller
  packages/console/app/src/routes/zen/util/provider/provider.ts  0% smaller
  packages/console/app/test/providerUsage.test.ts  0% smaller
  packages/console/app/vite.config.ts  0% smaller
  packages/console/core/script/create-api-key.ts  0% smaller
  packages/console/resource/resource.node.ts  0% smaller
  packages/core/package.json  0% smaller
  packages/core/src/flag/flag.ts  0% smaller
  packages/enterprise/vite.config.ts  0% smaller
  packages/opencode/package.json  0% smaller
  packages/opencode/src/acp-next/agent.ts  0% smaller
  packages/opencode/src/acp-next/event.ts  0% smaller
  packages/opencode/src/acp-next/session.ts  0% smaller
  packages/opencode/src/session/prompt.ts  0% smaller
  packages/opencode/src/tool/task_status.ts  0% smaller
  packages/opencode/src/tool/task_status.txt Unsupported file format
  packages/opencode/test/acp-next/event.test.ts  0% smaller
  packages/opencode/test/acp-next/service-session.test.ts  0% smaller
  packages/opencode/test/cli/run/scrollback.surface.test.ts  0% smaller
  packages/opencode/test/effect/runtime-flags.test.ts  0% smaller
  packages/opencode/test/server/httpapi-global.test.ts  0% smaller
  packages/opencode/test/server/httpapi-session.test.ts  0% smaller
  packages/opencode/test/server/worktree-endpoint-repro.test.ts  0% smaller
  packages/opencode/test/tool/__snapshots__/parameters.test.ts.snap Unsupported file format
  packages/opencode/test/tool/task_status.test.ts  0% smaller
  packages/sdk/js/src/v2/gen/types.gen.ts  0% smaller
  packages/sdk/openapi.json  0% smaller
  packages/stats/README.md Unsupported file format
  packages/stats/app/.gitignore Unsupported file format
  packages/stats/app/app.config.ts  0% smaller
  packages/stats/app/package.json  0% smaller
  packages/stats/app/src/app.css  0% smaller
  packages/stats/app/src/app.tsx  0% smaller
  packages/stats/app/src/asset/logo-ornate-dark.svg  0% smaller
  packages/stats/app/src/asset/logo-ornate-light.svg  0% smaller
  packages/stats/app/src/entry-client.tsx  0% smaller
  packages/stats/app/src/entry-server.tsx  0% smaller
  packages/stats/app/src/global.d.ts  0% smaller
  packages/stats/app/src/routes/api/health.ts  0% smaller
  packages/stats/app/src/routes/index.css  0% smaller
  packages/stats/app/src/routes/index.tsx  0% smaller
  packages/stats/app/sst-env.d.ts  0% smaller
  packages/stats/app/tsconfig.json  0% smaller
  packages/stats/app/vite.config.ts  0% smaller
  packages/stats/core/drizzle.config.ts  0% smaller
  packages/stats/core/migrations/20260522121617_common_dust/migration.sql Unsupported file format
  packages/stats/core/migrations/20260522121617_common_dust/snapshot.json  0% smaller
  packages/stats/core/migrations/20260523110335_cool_vin_gonzales/migration.sql Unsupported file format
  packages/stats/core/migrations/20260523110335_cool_vin_gonzales/snapshot.json  0% smaller
  packages/stats/core/package.json  0% smaller
  packages/stats/core/src/athena.ts  0% smaller
  packages/stats/core/src/config.ts  0% smaller
  packages/stats/core/src/database.ts  0% smaller
  packages/stats/core/src/database/schema.ts  0% smaller
  packages/stats/core/src/domain/geo.ts  0% smaller
  packages/stats/core/src/domain/home.ts  0% smaller
  packages/stats/core/src/domain/inference.ts  0% smaller
  packages/stats/core/src/domain/model.ts  0% smaller
  packages/stats/core/src/domain/provider.ts  0% smaller
  packages/stats/core/src/domain/stat.ts  0% smaller
  packages/stats/core/src/index.ts  0% smaller
  packages/stats/core/src/migrate.ts  0% smaller
  packages/stats/core/src/resource.d.ts  0% smaller
  packages/stats/core/src/runtime.ts  0% smaller
  packages/stats/core/src/stat-sync.ts  0% smaller
  packages/stats/core/sst-env.d.ts  0% smaller
  packages/stats/core/tsconfig.json  0% smaller
  packages/stats/server/Dockerfile Unsupported file format
  packages/stats/server/package.json  0% smaller
  packages/stats/server/src/ingest.ts  0% smaller
  packages/stats/server/src/resource.d.ts  0% smaller
  packages/stats/server/src/router.ts  0% smaller
  packages/stats/server/src/server.ts  0% smaller
  packages/stats/server/src/shutdown.ts  0% smaller
  packages/stats/server/src/stat-sync.ts  0% smaller
  packages/stats/server/sst-env.d.ts  0% smaller
  packages/stats/server/tsconfig.json  0% smaller
  packages/ui/src/v2/components/icon-button-v2.css  0% smaller
  packages/ui/src/v2/components/icon.tsx  0% smaller
  packages/ui/src/v2/styles/theme.css  0% smaller
  sst-env.d.ts  0% smaller
  sst.config.ts  0% smaller

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Copilot wasn't able to review this pull request because it exceeds the maximum number of files (300). Try reducing the number of changed files and requesting a review from Copilot again.

@github-actions
Copy link
Copy Markdown

Hey! Your PR title Personal copy of anomalyco/opencode#29208: fix(config): catch parse errors gracefully during startup doesn't follow conventional commit format.

Please update it to start with one of:

  • feat: or feat(scope): new feature
  • fix: or fix(scope): bug fix
  • docs: or docs(scope): documentation changes
  • chore: or chore(scope): maintenance tasks
  • refactor: or refactor(scope): code refactoring
  • test: or test(scope): adding or updating tests

Where scope is the package name (e.g., app, desktop, opencode).

See CONTRIBUTING.md for details.

@github-actions
Copy link
Copy Markdown

This PR doesn't fully meet our contributing guidelines and PR template.

What needs to be fixed:

  • PR description is missing required template sections. Please use the PR template.

Please edit this PR description to address the above within 2 hours, or it will be automatically closed.

If you believe this was flagged incorrectly, please let a maintainer know.

Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a significant architectural shift and UI overhaul across the OpenCode platform. Key updates include migrating the desktop application from Tauri to Electron, implementing a new tab-based navigation and composer design for non-production environments, and adding a referral reward system to the console. The codebase underwent a major refactoring to rename global SDK and sync providers to server-specific contexts, alongside infrastructure updates to monitoring and deployment regions. Review feedback highlights a critical accessibility concern regarding hidden streaming content, warns against breaking changes in custom provider configurations due to consolidated placeholders, and recommends using reactive state over direct DOM access in the prompt input component.

Comment thread packages/app/src/pages/session/message-timeline.tsx
Comment thread packages/console/app/src/routes/zen/util/handler.ts
Comment thread packages/app/src/components/prompt-input.tsx
@HaleTom
Copy link
Copy Markdown
Owner Author

HaleTom commented May 25, 2026

@gemini-code-assist please

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

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

Comments suppressed due to low confidence (1)

packages/opencode/src/config/config.ts:446

  • When config parsing/schema decoding fails, data falls back to an empty decoded Info, but the function still proceeds to the $schema auto-injection block. This can overwrite an invalid config file (or duplicate an existing $schema key) even though the file couldn't be parsed/validated, which is potentially destructive and can further corrupt the user's config.

Consider short-circuiting on parse/validation failure (e.g., return early for path sources) or tracking a parsedSuccessfully flag so plugin resolution and $schema auto-write only run when parsing/validation succeeded.

      const data = yield* Effect.sync(() => {
        const parsed = ConfigParse.jsonc(expanded, source)
        return ConfigParse.schema(Info, normalizeLoadedConfig(parsed, source), source)
      }).pipe(
        Effect.catchCause((cause) =>
          Effect.sync(() => {
            log.error("invalid config", { path: source, cause })
            return Schema.decodeSync(Info)({})
          }),
        ),
      )
      if (!("path" in options)) return data

      yield* Effect.promise(() => resolveLoadedPlugins(data, options.path)).pipe(
        Effect.catchCause((cause) =>
          Effect.sync(() => {
            log.error("plugin resolution failed", { path: source, cause })
          }),
        ),
      )
      if (!data.$schema) {
        data.$schema = "https://opencode.ai/config.json"
        const updated = text.replace(/^\s*\{/, '{\n  "$schema": "https://opencode.ai/config.json",')
        yield* fs.writeFileString(options.path, updated).pipe(Effect.catch(() => Effect.void))

@gemini-code-assist
Copy link
Copy Markdown

The implementation for graceful error handling using Effect.catchCause is well-structured and aligns with the Effect ecosystem. The added tests cover the necessary edge cases.

One minor suggestion:

In packages/opencode/src/config/config.ts, verify that your log.error implementation correctly serializes the cause object. If it's a standard logger, you might want to ensure it doesn't lose stack trace information or error details, which could be critical for debugging configuration issues.

Severity: low

@HaleTom HaleTom reopened this May 26, 2026
Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

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

No issues found across 2 files

Re-trigger cubic

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

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

Comment on lines +76 to +82
function stripUnknownKeys(data: unknown): unknown {
if (typeof data !== "object" || data === null || Array.isArray(data)) return data
const known = new Set(Info.ast.propertySignatures.map((p) => String(p.name)))
const result: Record<string, unknown> = {}
for (const [key, value] of Object.entries(data)) {
if (known.has(key)) result[key] = value
else log.warn("config key is not recognized and will be ignored", { key })
Comment on lines +445 to +454
Effect.catchCause((cause) =>
Effect.sync(() => {
const errors = cause.reasons
.filter(Cause.isDieReason)
.map((r) => (r.defect instanceof Error ? r.defect.name : "UnknownError"))
.join(", ")
log.error("invalid config: config file could not be parsed", { path: source, error: errors })
return {} as Info
}),
),
Comment on lines +642 to +651
it.instance("handles plugin resolution failure gracefully", () =>
Effect.gen(function* () {
const test = yield* TestInstance
yield* writeConfigEffect(test.directory, {
$schema: "https://opencode.ai/config.json",
model: "has-plugin",
plugin: ["./non-existent-plugin.ts"],
})
const config = yield* Config.use.get()
expect(config.model).toBe("has-plugin")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.