Skip to content

fix(config): guard env-var JSON parsing against invalid input#28250

Draft
kitlangton wants to merge 1 commit into
devfrom
fix-env-json-parse-guards
Draft

fix(config): guard env-var JSON parsing against invalid input#28250
kitlangton wants to merge 1 commit into
devfrom
fix-env-json-parse-guards

Conversation

@kitlangton
Copy link
Copy Markdown
Contributor

@kitlangton kitlangton commented May 18, 2026

Summary

Two unguarded JSON.parse(<env var>) calls at config boundaries used to crash startup on malformed input. After a design pass we landed on a principled split:

  • Fail loud on safety boundaries (OPENCODE_PERMISSION). Silently defaulting to "no restrictions" when the user intended restrictions is dangerous.
  • Warn and ignore on UX-preference boundaries (OPENCODE_ROUTE). Falling back to the home route is benign.

Both behaviors now flow through a tiny shared helper module so future env-var-fed config boundaries pick the appropriate side without re-implementing JSON-parse + schema-decode + log-or-throw plumbing each time.

New helpers — packages/opencode/src/util/json.ts

  • InvalidConfigErrorSchema.TaggedErrorClass carrying { source, value, reason }. The reason is the Schema issue's stringification, so the error always names which field is wrong.
  • requireJsonConfig(raw, schema, source): S["Type"] — synchronously throws InvalidConfigError on malformed JSON or schema mismatch. Used at safety boundaries.
  • tryJsonConfig(raw, schema, source): Option<S["Type"]> — returns None for absent / empty / malformed / shape-mismatched input, logging a structured warn so the user can debug. Used at preference boundaries.

Both share the same underlying decode pipeline (Schema.UnknownFromJsonStringSchema.decodeUnknownResult(schema)); they only differ in how they signal failure.

Surfaces updated

  • packages/opencode/src/config/config.tsOPENCODE_PERMISSION now uses requireJsonConfig(..., ConfigPermission.Info, "OPENCODE_PERMISSION"). The previous warn-and-skip path is gone; an invalid permission env-var halts startup. Closes OPENCODE_PERMISSION JSON parsing crashes on invalid input #28206.
  • packages/opencode/src/cli/cmd/tui/context/route.tsxOPENCODE_ROUTE now uses tryJsonConfig(..., RouteSchema, "OPENCODE_ROUTE") with a tight Schema.Union covering the three Route variants the env-var realistically carries. Falls back to HOME_ROUTE on None.
  • packages/opencode/src/cli/error.tsFormatError now matches InvalidConfigError and renders a multi-line friendly message before process.exit(1) instead of dumping a stack trace.

The helpers are positioned to be used by #28172 (theme env var) and the future OPENCODE_AUTH_CONTENT work — both are UX-preference boundaries that fit tryJsonConfig cleanly.

Test coverage

  • packages/opencode/test/util/json.test.ts — 9 tests covering requireJsonConfig (success, malformed JSON, shape mismatch, _tag shape) and tryJsonConfig (success, undefined, empty, malformed JSON, shape mismatch) with a synthetic PointSchema.
  • packages/opencode/test/config/permission-env.test.ts — 5 tests asserting InvalidConfigError carries the right source/value/reason on malformed JSON and shape mismatch, plus success paths for Action shorthand, flat rules, and nested per-pattern bash rules.
  • packages/opencode/test/cli/tui/route-env.test.ts — 7 tests covering None for undefined / empty / malformed JSON / schema mismatch, and Some for home / session / plugin routes.

Test plan

  • bun typecheck in packages/opencode (clean)
  • bun run test test/util/json.test.ts (9 pass)
  • bun run test test/config/permission-env.test.ts (5 pass)
  • bun run test test/cli/tui/route-env.test.ts (7 pass)
  • bun run test test/config/ (168 pass, no regressions)
  • Manual: start opencode with OPENCODE_PERMISSION='not json' and confirm startup halts with the formatted InvalidConfigError message (no stack trace)
  • Manual: start opencode with OPENCODE_PERMISSION='{"bash":"banana"}' and confirm the same friendly halt with a "banana is not a valid Action" reason
  • Manual: start opencode-tui with OPENCODE_ROUTE='not json' and confirm it falls back to the home route with a warn log

@kitlangton kitlangton force-pushed the fix-env-json-parse-guards branch from d219b2e to 57e24bd Compare May 18, 2026 23:22
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.

OPENCODE_PERMISSION JSON parsing crashes on invalid input

1 participant