multica-ai/multica · error
encode CLI config: %w
Error message
encode CLI config: %w
What it means
json.MarshalIndent failed while serializing CLIConfig before writing. For a plain struct config this is practically unreachable unless the struct contains a channel, func, or circular reference — none of which the CLI config is expected to have. Seeing it usually means the struct definition was extended with a non-serializable field.
Source
Thrown at server/internal/cli/config.go:350
if err != nil {
return fmt.Errorf("resolve task-local CLI config root: %w", err)
}
for current := dir; ; current = filepath.Dir(current) {
if err := os.Chmod(current, 0o700); err != nil {
return fmt.Errorf("restrict task-local CLI config directory: %w", err)
}
if current == root {
break
}
parent := filepath.Dir(current)
if parent == current {
return fmt.Errorf("task-local CLI config directory %q escapes root %q", dir, root)
}
}
}
data, err := json.MarshalIndent(cfg, "", " ")
if err != nil {
return fmt.Errorf("encode CLI config: %w", err)
}
// Write to a temp file in the same directory, then rename for atomicity.
tmp, err := os.CreateTemp(dir, ".config-*.json.tmp")
if err != nil {
return fmt.Errorf("create temp config file: %w", err)
}
tmpPath := tmp.Name()
if _, err := tmp.Write(append(data, '\n')); err != nil {
tmp.Close()
os.Remove(tmpPath)
return fmt.Errorf("write temp config file: %w", err)
}
if err := tmp.Close(); err != nil {
os.Remove(tmpPath)
return fmt.Errorf("close temp config file: %w", err)
}
if err := os.Chmod(tmpPath, 0o600); err != nil {View on GitHub (pinned to 2c0912b6ec)
Solutions
- Tag any non-serializable field with `json:"-"` so Marshal skips it
- Replace func/chan fields with serializable representations (names, IDs) in the persisted struct
- Add a unit test that round-trips CLIConfig through json.Marshal to catch regressions early
Example fix
// before
type CLIConfig struct {
Debug bool `json:"debug"`
Log chan string `json:"log"` // unsupported type: chan
}
// after
type CLIConfig struct {
Debug bool `json:"debug"`
Log chan string `json:"-"` // runtime-only, never serialized
} Defensive patterns
Strategy: try-catch
Try / catch
if _, err := json.Marshal(cfg); err != nil {
// config struct contains unsupported field types; fix before save
} Prevention
- Keep CLIConfig fields limited to JSON-serializable types
- Mark runtime-only fields with json:"-"
- Add a round-trip marshal unit test for CLIConfig
When it happens
Trigger: Adding a field of type chan, func, or complex to CLIConfig and then calling SaveCLIConfig; a map with non-string keys or a self-referencing type added during development.
Common situations: Developers extending CLIConfig with a logger callback or a channel and forgetting json:"-" tags.
Related errors
- body must be a JSON object or array
- --runtime-config must be valid JSON: %w
- %s must be a JSON object, or 'null' to clear
- %s must be a JSON object
- --runtime-config must be valid JSON: %w
AI-assisted analysis of multica-ai/multica@2c0912b6ec (2026-08-15).
Data as JSON: /api/errors/a5f708d229fbe56c.
Report an issue: GitHub.