gastownhall/beads · error
invalid --set-metadata: expected key=value, got %q
Error message
invalid --set-metadata: expected key=value, got %q
What it means
ApplyMetadataEdits parses each entry of setFlags as key=value using strings.Cut and rejects any entry with no '=' separator or an empty key. The library throws this so malformed --set-metadata flags are caught at edit time rather than silently creating wrong keys. The offending flag is echoed with %q for easy identification.
Source
Thrown at internal/storage/metadata.go:293
// ApplyMetadataEdits applies incremental set (key=value) and unset (key) edits
// to existing metadata and returns the merged JSON. Set values are typed via
// MetadataEditValue; keys are validated with ValidateMetadataKey.
func ApplyMetadataEdits(existing json.RawMessage, setFlags, unsetFlags []string) (json.RawMessage, error) {
data := make(map[string]json.RawMessage)
if len(existing) > 0 {
trimmed := strings.TrimSpace(string(existing))
if trimmed != "" && trimmed != "null" {
if err := json.Unmarshal(existing, &data); err != nil {
return nil, fmt.Errorf("existing metadata is not a JSON object: %w", err)
}
}
}
for _, kv := range setFlags {
k, v, ok := strings.Cut(kv, "=")
if !ok || k == "" {
return nil, fmt.Errorf("invalid --set-metadata: expected key=value, got %q", kv)
}
if err := ValidateMetadataKey(k); err != nil {
return nil, err
}
data[k] = MetadataEditValue(v)
}
for _, k := range unsetFlags {
if err := ValidateMetadataKey(k); err != nil {
return nil, err
}
delete(data, k)
}
result, err := json.Marshal(data)
if err != nil {
return nil, fmt.Errorf("failed to marshal metadata: %w", err)
}View on GitHub (pinned to 71377f2769)
Solutions
- Rewrite the flag as key=value: --set-metadata owner=alice.
- If the value itself must contain '=', everything after the first '=' is the value (strings.Cut splits only once), so do not escape it.
- If the value contains spaces, quote the whole argument: --set-metadata "note=some text here".
- Check the flag list for empty strings left by over-quoting (e.g. --set-metadata "" produces this error).
Example fix
// before bd update bd-1 --set-metadata owner // no '=' // after bd update bd-1 --set-metadata owner=alice
Defensive patterns
Strategy: validation
Validate before calling
func validSetFlag(f string) bool {
k, _, ok := strings.Cut(f, "=")
return ok && k != ""
}
// check every --set-metadata flag in the caller before invoking ApplyMetadataEdits
for _, f := range setFlags {
if !validSetFlag(f) { return fmt.Errorf("bad flag %q", f) }
} Try / catch
out, err := ApplyMetadataEdits(existing, setFlags, unsetFlags)
if err != nil && strings.Contains(err.Error(), "invalid --set-metadata") {
return fmt.Errorf("usage: --set-metadata key=value (got: %v)", err)
} Prevention
- Always write --set-metadata as key=value; quote arguments containing spaces.
- Remember only the first '=' splits; values may contain '=' freely.
- Check for empty-string flags caused by over-quoting in scripts.
When it happens
Trigger: Passing a set flag like "mykey" (no =), "=value" (empty key), or "" (empty string) in the setFlags slice — e.g. `bd update bd-1 --set-metadata owner` instead of `--set-metadata owner=alice`.
Common situations: Shell splitting an argument containing spaces so only part of key=value arrives; forgetting the '=' when the value looks optional; copy-pasting flag docs that show key and value as separate words.
Related errors
- invalid --set-metadata: expected key=value, got %q
- invalid variable format '%s', expected 'key=value'
- invalid dependency format %q, expected 'type:id' or 'id'
- cannot combine %s
- resolving issue ID %q: %w (to %s multiple labels, pass one c
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/58eb68feefcce14e.
Report an issue: GitHub.