Skip to content

[BUG]: Partial formatter override silently dropped when command is not specified #14857

@rcdailey

Description

@rcdailey

Verify there isn't already a bug report for this.

  • I have verified there isn't already an open bug report for this.

Describe the bug

When overriding a built-in formatter's extensions without also specifying command, the entire override is silently discarded and the built-in defaults (including all original extensions) remain active.

For example, this config intends to prevent prettier from formatting .md files:

"formatter": {
  "prettier": {
    "extensions": [".js", ".jsx", ".ts", ".tsx", ".css", ".scss", ".json", ".yaml", ".yml"]
  }
}

But prettier still formats .md files because the override is never applied.

Root cause

In packages/opencode/src/format/index.ts, user config is merged via:

const result: Formatter.Info = mergeDeep(formatters[name] ?? {}, {
  command: [],
  extensions: [],
  ...item,
})

if (result.command.length === 0) continue

The command: [] stub is spread before ...item. Since the user only provided extensions, command stays as []. mergeDeep uses replace semantics for arrays (not deep merge), so the empty array replaces the built-in command. The command.length === 0 guard then fires, skipping the override entirely. The original built-in formatter config (with all default extensions) remains.

Expected behavior

Partial overrides of built-in formatters should preserve unspecified fields. Overriding only extensions should keep the built-in command intact.

Workaround

Explicitly include the command in the override:

"formatter": {
  "prettier": {
    "command": ["npx", "prettier", "--write", "$FILE"],
    "extensions": [".js", ".jsx", ".ts", ".tsx", ".css", ".scss", ".json", ".yaml", ".yml"]
  }
}

OpenCode version

Latest (verified against current dev branch source)

Metadata

Metadata

Assignees

Labels

coreAnything pertaining to core functionality of the application (opencode server stuff)

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions