Skip to content

serve: a config load error is cached per project instance — fixing/deleting the offending command file does not clear it until /global/dispose #50906

Closed as not planned

Description

@Ron-RONZZ-org

Description

On a long-lived opencode serve, configuration is loaded once per project instance and cached for the process lifetime. When that initial load fails validation, the failure is cached too: fixing (or even deleting) the offending file does not clear it. Every subsequent opencode attach --dir <project> keeps failing with the same error until /global/dispose is called or the server is restarted, with no in-product hint that this is stale state.

The concrete trigger I hit: a command file whose frontmatter has an empty value:

---
description:
agent: copilot
---

An empty YAML value parses to null. The command schema (packages/core/src/v1/config/command.ts) declares description: Schema.optional(Schema.String) = string | undefined, so null fails:

Configuration is invalid at /path/.opencode/commands/<name>.md: SchemaError: Expected string | undefined, got null
  at ["description"]

The user then fills in a description (or removes the file), retries, and gets the identical error — the server is still serving the cached failed load.

Steps to reproduce

  1. Start a long-lived server in a scratch dir: opencode serve --port 4096
  2. In a project, create .opencode/commands/foo.md:
    ---
    description:
    agent: copilot
    ---
    body
  3. opencode attach http://127.0.0.1:4096 --dir <project> → SchemaError: Expected string | undefined, got null at ["description"]
  4. Edit the file to give description a value — or delete the file entirely.
  5. opencode attach http://127.0.0.1:4096 --dir <project> again → the same error, for the deleted file path.
  6. POST http://127.0.0.1:4096/global/dispose (or a fresh opencode serve on another port, same --dir) → the project loads cleanly.

Actual

  • The parse failure is cached in the per-project instance (InstanceStore); config is not re-read on file change.
  • A transient authoring mistake becomes a sticky, unrecoverable-looking startup failure.
  • The error message names the file but gives no hint that the file has already been fixed or that a reload is required.

Expected

Any of:

  • The instance is invalidated when a config/command/agent file changes (or at least when a previous load failed), so the next use re-reads from disk; or
  • A failed config load is not cached permanently; or
  • At minimum, the error surfaces an explicit remediation hint (e.g. "config is cached; run /global/dispose / reload to retry").

Separately and trivially: since the field is optional, coercing an empty frontmatter value (null) to undefined for description/agent/model would prevent the most common form of this trap.

Root cause (v1.18.25)

  • packages/opencode/src/config/command.ts — ConfigCommand.load() throws InvalidError on the first command that fails schema decode.
  • packages/core/src/v1/config/command.ts — description: Schema.optional(Schema.String); empty YAML → null.
  • packages/core/src/config/markdown.ts — gray-matter yields null for an empty value.
  • Config is loaded once per instance in InstanceStore; the failed state persists until POST /global/dispose (Server.disposeAllInstances…).

Impact

Any persistent serve deployment (headless/multi-attach) is affected. A single bad frontmatter edit — including one made by another agent/build step — wedges the project's config until someone knows the undocumented dispose endpoint. This is the same class of "rewrite a config file under a live server and state never recovers" as #46245 (agents), but here it manifests as a hard validation error rather than empty responses.

Related

Environment

  • OpenCode 1.18.25
  • Linux Mint 22.1 (Debian-based), kernel 6.8.0-107
  • Long-lived opencode serve --port 4096 + multiple opencode attach --dir . clients
  • Plugins: opencode-notify; local worktree/mcp-daemon/browser-safety plugins

Activity

  1. holny commented on Sep 23, 2026

    @holny
    Contributor

    I'll take this. Reproduction paths line up with the per-project instance cache in InstanceStore: a config parse failure is stored as the instance's config state, so after the offending file is fixed or deleted nothing re-runs the load and every attach keeps reading the same cached failure.

    Plan: make the failed load non-sticky for config — either wait for the location watcher's invalidation to re-attempt the load, or clear the cached failure when the offending path changes/disappears. Both attached and fresh sessions need to see the corrected state without a /global/dispose, and the cache should keep succeeding loads as they are.

    I'll also add a regression that seeds a bad config, attaches, fixes the file, and asserts the next attach succeeds.

    Fixes #50906

  2. thdxr commented on Oct 11, 2026

    @thdxr
    Member

    Thanks for the report! OpenCode 2.0 is now out and development is focused on V2, so we're closing issues filed against OpenCode 1. Please upgrade (opencode upgrade --major, details: https://anoma.ly/notes/opencode-2-0), and if this is still relevant on 2.0, reopen this issue or open a new one with your 2.0 version.

    — from 𝕺𝖕𝖊𝖓𝕮𝖔𝖉𝖊

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions