{"record":{"id":"51e31c7de631f4eb","repo":"gastownhall/beads","slug":"invalid-metadata-w","errorCode":null,"errorMessage":"invalid metadata: %w","messagePattern":"invalid metadata: %w","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/storage/dolt/issues.go","lineNumber":175,"sourceCode":"\t})\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn s.GetIssue(ctx, id)\n}\n\n// validateUpdateMetadata validates an inbound metadata update value against the\n// configured schema (GH#1416 Phase 2) before any wisp routing. It is a no-op\n// when the update carries no \"metadata\" key. Shared by UpdateIssue and\n// UpdateIssueChecked so both apply the identical pre-write validation.\nfunc validateUpdateMetadata(updates map[string]interface{}) error {\n\trawMeta, ok := updates[\"metadata\"]\n\tif !ok {\n\t\treturn nil\n\t}\n\tmetadataStr, err := storage.NormalizeMetadataValue(rawMeta)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"invalid metadata: %w\", err)\n\t}\n\treturn validateMetadataIfConfigured(json.RawMessage(metadataStr))\n}\n\n// checkExpectedVersionInTx enforces the optional ExpectedVersion CAS\n// precondition inside tx: when expectedVersion is non-nil the row's current\n// RowVersion (row_lock) must still equal it, else the caller's transaction\n// returns storage.ErrVersionMismatch and rolls back with the issue unchanged. A\n// nil expectedVersion disables the check (an unconditional update).\nfunc checkExpectedVersionInTx(ctx context.Context, tx *sql.Tx, id string, expectedVersion *int64) error {\n\tif expectedVersion == nil {\n\t\treturn nil\n\t}\n\treturn issueops.CheckVersionInTx(ctx, tx, id, *expectedVersion)\n}\n\n// UpdateIssue updates fields on an issue.\n// Delegates SQL work to issueops.UpdateIssueInTx; handles Dolt-specific concerns","sourceCodeStart":157,"sourceCodeEnd":193,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/dolt/issues.go#L157-L193","documentation":"This error wraps failures from NormalizeMetadataValue and validateMetadataIfConfigured during an issue update whose updates map contains a \"metadata\" key. It means the metadata value supplied is not valid JSON, cannot be normalized to a canonical form, or violates configured metadata validation policy. The underlying wrapped error tells which stage failed.","triggerScenarios":"Calling updateIssue/updateIssueChecked (e.g. via bd update) with updates[\"metadata\"] set to a non-JSON string, malformed JSON, or metadata that fails schema validation when validation is configured.","commonSituations":"Shell quoting mangles JSON (single vs double quotes), passing a bare string instead of a JSON object, partial writes by scripts, or enabling metadata validation rules that existing metadata no longer satisfies.","solutions":["Print the raw metadata string being passed and validate it with a JSON parser (jq) before calling update","Re-run the update with properly quoted JSON, e.g. bd update bd-1 --metadata='{\"key\":\"value\"}' or use --metadata=- with stdin","If validation is configured, check the metadata against the configured schema and fix the offending fields","If the stored value is corrupt, read the current metadata, fix it locally, and rewrite it in one update"],"exampleFix":"// before\nbd update bd-42 --metadata=key:value\n// after\nbd update bd-42 --metadata='{\"key\":\"value\"}'","handlingStrategy":"validation","validationCode":"const meta = '{\"priority\":1}';\nif (!/^[\\s\\S]*$/.test(meta)) throw new Error(\"empty\");\ntry { JSON.parse(meta); } catch (e) { throw new Error(`metadata is not valid JSON: ${e.message}`); }","typeGuard":"function isJSONObject(v) {\n  if (typeof v !== \"string\") return false;\n  try { const p = JSON.parse(v); return p !== null && typeof p === \"object\" && !Array.isArray(p); } catch { return false; }\n}","tryCatchPattern":"try {\n  await bd.update(id, { metadata });\n} catch (e) {\n  if (String(e.message).includes(\"invalid metadata\")) {\n    console.error(\"Metadata rejected:\", e.cause ?? e.message);\n  } else throw e;\n}","preventionTips":["Always pass metadata as a JSON object and validate with jq or JSON.parse before calling update","Use stdin (--metadata=-) for complex JSON to avoid shell quoting issues","Keep a schema for metadata fields and validate inputs against it","Check configured metadata validation rules before writing metadata"],"tags":["metadata","validation","json","storage"],"backgroundTag":"metadata-validation-failed","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}