gastownhall/beads · error
invalid %s value: %v
Error message
invalid %s value: %v
What it means
ValidateSettingWrite validates status.custom values by parsing them with types.ParseCustomStatusConfig before the value can be stored, wrapping issueops.ErrValidation. status.custom is projected into the custom_statuses table that readers consult first, so a value that cannot be projected must never become a row. Checking here makes the refusal a clean validation error rather than a later storage failure.
Source
Thrown at internal/workapi/workspaceconfig.go:61
return "", err
}
// The prefix is owned by bd init --prefix, bd bootstrap and bd
// rename-prefix. Refused HERE rather than at the front door because `bd
// config set` is not the only door that reaches this plane: before this
// role existed `bd config set-many issue_prefix=x` walked past the guard
// and re-prefixed the workspace.
if key == issueops.SettingKeyIssuePrefix || key == "issue-prefix" {
return "", fmt.Errorf("%w: %q is set by bd init --prefix, bd bootstrap or bd rename-prefix, not by a config write: "+
"storing it here would leave existing ids under the old prefix with nothing to reconcile them",
issueops.ErrValidation, key)
}
// status.custom is PROJECTED into custom_statuses, which reads consult
// first, so a value that cannot be projected must not become a row.
// Checking here rather than leaving it to SyncCustomStatusesTable is what
// makes the refusal a validation error rather than a storage failure.
if key == issueops.SettingKeyStatusCustom && value != "" {
if _, err := types.ParseCustomStatusConfig(value); err != nil {
return "", fmt.Errorf("%w: invalid %s value: %v", issueops.ErrValidation, key, err)
}
}
return value, nil
}
// FilterSettingsEnumeration takes the rows a store handed back and returns the
// ones the settings enumeration is allowed to carry: everything except the KV
// plane.
//
// THE KV PLANE RIDES IN THE SAME TABLE AND IS NOT SETTINGS. Generic `bd kv`
// keys and the `bd remember` memories nested under them are USER DATA stored as
// config rows beneath kvkeys.Prefix, and an enumeration that returned them
// published that data on `bd config list` and on GET /v0/beads/config alike —
// the latter reachable by anything a shared bearer admits, if one is
// configured at all, and redacting on the KEY NAME while a memory's content is
// in the VALUE. `bd config list` carrying kv rows was never a
// design; it fell out of one storage table holding two planes.
//View on GitHub (pinned to 71377f2769)
Solutions
- Validate the value locally with types.ParseCustomStatusConfig(value) and fix the structure before storing
- Use the canonical JSON shape for custom statuses (check the parser for required fields)
- Prefer dedicated commands for managing custom statuses rather than raw config writes where available
Example fix
// before
bd config set status.custom='{"label":"in-progress"}'
// after
bd config set status.custom='{"label":"in-progress","count":null,"order":0}' Defensive patterns
Strategy: validation
Validate before calling
if _, err := types.ParseCustomStatusConfig(value); err != nil {
return fmt.Errorf("status.custom is not valid: %v", err)
} Type guard
func validCustomStatus(v string) bool { _, err := types.ParseCustomStatusConfig(v); return err == nil } Try / catch
_, err := workapi.ValidateSettingWrite("status.custom", val)
if errors.Is(err, issueops.ErrValidation) { /* show parse error, do not retry as-is */ } Prevention
- Pre-validate status.custom with types.ParseCustomStatusConfig before storing
- Build custom-status JSON programmatically instead of hand-writing it
- Beware shell quoting mangling JSON; use single quotes or heredocs
- Keep custom-status configs aligned with the current schema when upgrading
When it happens
Trigger: Calling ValidateSettingWrite("status.custom", <malformed value>) with a non-empty value that ParseCustomStatusConfig rejects, e.g. bd config set status.custom='not-json' or a structurally invalid custom-status config.
Common situations: Hand-editing status.custom values with typos or wrong JSON structure; migrating configs between schema versions where the custom-status format changed; shell quoting mangling the JSON before it reaches the API.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
- duplicate custom status name %q
- server: NewDoltServer: doltBinExec is required
- server: NewDoltServer: rootDir is required
- server: NewDoltServer: configPath is required
- ErrPrefixMismatch
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/042699b3ec244649.
Report an issue: GitHub.