gastownhall/beads · error
%q is set by bd init --prefix, bd bootstrap or bd rename-pre
Error message
%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
What it means
ValidateSettingWrite refuses to store the issue-prefix setting under either spelling (issue_prefix or issue-prefix), wrapping issueops.ErrValidation. The prefix is owned exclusively by bd init --prefix, bd bootstrap, and bd rename-prefix; storing it via a plain config write would leave existing IDs under the old prefix with nothing to reconcile them. The guard sits here rather than at the CLI front door because config set-many previously bypassed it.
Source
Thrown at internal/workapi/workspaceconfig.go:51
return "", fmt.Errorf("%w: config key must not be empty", issueops.ErrValidation)
}
return key, nil
}
// ValidateSettingWrite checks a key and value a caller wants to STORE, and
// returns the value as it will be stored, so that a body cannot store a
// different string from the one that was checked.
func ValidateSettingWrite(key, value string) (string, error) {
if _, err := ValidateSettingKey(key); err != nil {
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.View on GitHub (pinned to 71377f2769)
Solutions
- Use bd rename-prefix to change the prefix so existing IDs are reconciled
- For new workspaces use bd init --prefix or bd bootstrap instead of a config write
- Remove issue_prefix/issue-prefix from any config set/set-many scripts and write only non-protected keys
Example fix
// before bd config set issue_prefix=NEW // after bd rename-prefix NEW
Defensive patterns
Strategy: validation
Validate before calling
var protectedKeys = map[string]bool{"issue_prefix": true, "issue-prefix": true}
if protectedKeys[key] { return fmt.Errorf("use bd rename-prefix to change %s", key) } Type guard
func isPrefixKey(k string) bool { return k == "issue_prefix" || k == "issue-prefix" } Try / catch
_, err := workapi.ValidateSettingWrite(key, val)
if errors.Is(err, issueops.ErrValidation) && isPrefixKey(key) { /* route to bd rename-prefix flow */ } Prevention
- Treat issue_prefix/issue-prefix as reserved and filter them out of bulk config writes
- Use bd rename-prefix, bd init --prefix, or bd bootstrap for all prefix changes
- Audit automation scripts for hardcoded prefix config writes
When it happens
Trigger: Calling ValidateSettingWrite("issue_prefix", x) or ValidateSettingWrite("issue-prefix", x), e.g. via bd config set issue_prefix=NEW or bd config set-many issue_prefix=x.
Common situations: Trying to rename a workspace prefix by hand through config instead of bd rename-prefix; copy-pasted setup scripts from before the dedicated commands existed; automation that writes all settings wholesale including the prefix.
Related errors
- %w: issue ID %s does not match configured prefix %s
- 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/6e26ee7010e0cd4f.
Report an issue: GitHub.