Description
When aft.jsonc contains // line comments or /* */ block comments above object keys, comment-json@4.6.2 attaches Symbol.for(...) properties to the parsed result to track comment positions. AFT passes this object directly to AftConfigSchema.safeParse(rawConfig) (Zod), which iterates all own properties including Symbol keys. Zod attempts to convert these Symbol keys to strings for path construction and throws:
TypeError: Cannot convert a symbol to a string
This causes the entire config loading to fail silently (caught by the try/catch in loadConfigFromPath), resulting in search_index, semantic_search, and all other settings falling back to their defaults (disabled).
Expected Behavior
aft.jsonc with comments should load correctly, since comments are a core JSONC feature and AFT documentation states "Both files are JSONC (comments allowed)".
Steps to Reproduce
- Add any
// comment above a key inside a nested object in aft.jsonc, e.g.:
- Restart OpenCode
- Check
aft-plugin.log — error: Cannot convert a symbol to a string
- Check
/aft-status — search_index and semantic_search show as disabled
Root Cause
In packages/opencode-plugin/src/config.ts, loadConfigFromPath():
const rawConfig = parseJsonc<Record<string, unknown>>(content); // attaches Symbol props
migrateRawConfig(rawConfig, configPath, { log, warn });
const result = AftConfigSchema.safeParse(rawConfig); // Zod crashes on Symbol keys
comment-json.parse() returns objects with Symbol.for("before:<key>") properties. No cleanup is performed between parseJsonc and safeParse.
Suggested Fix
Strip Symbol properties before Zod validation. Options:
- Use
comment-json built-in removeComments() before safeParse:
const cleaned = removeComments(rawConfig);
const result = AftConfigSchema.safeParse(cleaned);
- Manually strip Symbol keys with a recursive helper:
function stripSymbols(obj: unknown): unknown {
if (typeof obj !== "object" || obj === null) return obj;
if (Array.isArray(obj)) return obj.map(stripSymbols);
const out: Record<string, unknown> = {};
for (const [k, v] of Object.entries(obj)) out[k] = stripSymbols(v);
return out;
}
Environment
- AFT: v0.34.0
- OS: macOS arm64 (darwin)
- Node: v25.8.2
- OpenCode: 1.15.13
- comment-json: 4.6.2 (bundled)
Workaround
Remove all comments from aft.jsonc (use strict JSON format without // or /* */ comments).
Description
When
aft.jsonccontains//line comments or/* */block comments above object keys,comment-json@4.6.2attachesSymbol.for(...)properties to the parsed result to track comment positions. AFT passes this object directly toAftConfigSchema.safeParse(rawConfig)(Zod), which iterates all own properties including Symbol keys. Zod attempts to convert these Symbol keys to strings for path construction and throws:This causes the entire config loading to fail silently (caught by the try/catch in
loadConfigFromPath), resulting insearch_index,semantic_search, and all other settings falling back to their defaults (disabled).Expected Behavior
aft.jsoncwith comments should load correctly, since comments are a core JSONC feature and AFT documentation states "Both files are JSONC (comments allowed)".Steps to Reproduce
//comment above a key inside a nested object inaft.jsonc, e.g.:{ "lsp": { "servers": { // My custom server "my-server": { "binary": "my-lsp" } } } }aft-plugin.log— error:Cannot convert a symbol to a string/aft-status—search_indexandsemantic_searchshow as disabledRoot Cause
In
packages/opencode-plugin/src/config.ts,loadConfigFromPath():comment-json.parse()returns objects withSymbol.for("before:<key>")properties. No cleanup is performed betweenparseJsoncandsafeParse.Suggested Fix
Strip Symbol properties before Zod validation. Options:
comment-jsonbuilt-inremoveComments()beforesafeParse:Environment
Workaround
Remove all comments from
aft.jsonc(use strict JSON format without//or/* */comments).