gastownhall/beads · error
invalid metadata: %w
Error message
invalid metadata: %w
What it means
The metadata value supplied to updateIssueInTx failed storage.NormalizeMetadataValue, so it cannot be serialized into the metadata column. The underlying normalization error is wrapped as "invalid metadata: %w".
Source
Thrown at internal/storage/issueops/update.go:442
for key, value := range updates {
if !IsAllowedUpdateField(key) {
return nil, fmt.Errorf("invalid field for update: %s", key)
}
columnName := key
if key == "wisp" {
columnName = "ephemeral"
}
setClauses = append(setClauses, fmt.Sprintf("`%s` = ?", columnName))
// Handle JSON serialization for array fields stored as TEXT.
if key == "waiters" {
waitersJSON, _ := json.Marshal(value)
args = append(args, string(waitersJSON))
} else if key == "metadata" {
metadataStr, err := storage.NormalizeMetadataValue(value)
if err != nil {
return nil, fmt.Errorf("invalid metadata: %w", err)
}
args = append(args, metadataStr)
} else {
args = append(args, value)
}
}
// Auto-clear pinned column when status transitions away from "pinned".
if rawStatus, ok := updates["status"]; ok {
var statusStr string
switch v := rawStatus.(type) {
case string:
statusStr = v
case types.Status:
statusStr = string(v)
}
if oldIssue.Pinned && statusStr != string(types.StatusPinned) {
if _, alreadySet := updates["pinned"]; !alreadySet {View on GitHub (pinned to 71377f2769)
Solutions
- Convert metadata to map[string]string before assigning it to updates["metadata"].
- Inspect the wrapped error (errors.Unwrap / %w chain) for the specific normalization failure.
- Marshal then unmarshal through map[string]string to coerce values: convert each value with fmt.Sprintf if needed.
Example fix
// before
updates["metadata"] = rawMetadata // map[string]interface{}
// after
m := map[string]string{}
for k, v := range rawMetadata {
m[k] = fmt.Sprintf("%v", v)
}
updates["metadata"] = m Defensive patterns
Strategy: validation
Validate before calling
if raw, ok := updates["metadata"]; ok {
if _, err := storage.NormalizeMetadataValue(raw); err != nil {
return fmt.Errorf("metadata must normalize: %w", err)
}
} Type guard
func asStringMap(v interface{}) (map[string]string, bool) {
m, ok := v.(map[string]string)
return m, ok
} Try / catch
if _, err := storage.UpdateIssue(ctx, id, updates, actor); err != nil {
if strings.Contains(err.Error(), "invalid metadata") {
return fmt.Errorf("fix metadata shape (map[string]string): %w", err)
}
return err
} Prevention
- Always pass metadata as map[string]string.
- Coerce JSON-decoded values (map[string]interface{}) to strings before assigning.
- Validate metadata with NormalizeMetadataValue before the update call.
- Keep metadata values small, flat, and string-typed.
When it happens
Trigger: Passing a metadata value that is not a map[string]string (e.g. nested maps, non-string values, nil of wrong shape) or a JSON string that does not normalize cleanly when calling UpdateIssueInTx with key "metadata".
Common situations: JSON-decoded metadata containing numbers/bools instead of strings; callers passing structs rather than string maps; mixing metadata formats between versions of the schema.
Related errors
- invalid metadata: %w
- no store is open for this workspace
- not found
- ExternalDoltConfig: must set Socket or (Host, Port)
- db: ChildCounterSQLRepository.NextChildID: parentID must not
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/ab346a6f4f213274.
Report an issue: GitHub.