{"record":{"id":"3f8a1edea3946d22","repo":"gastownhall/beads","slug":"metadata-is-not-valid-json","errorCode":null,"errorMessage":"metadata is not valid JSON","messagePattern":"metadata is not valid JSON","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/storage/metadata.go","lineNumber":32,"sourceCode":"//\n// This supports GH#1417: allow UpdateIssue metadata updates via json.RawMessage/[]byte.\nfunc NormalizeMetadataValue(value interface{}) (string, error) {\n\tvar jsonStr string\n\n\tswitch v := value.(type) {\n\tcase string:\n\t\tjsonStr = v\n\tcase []byte:\n\t\tjsonStr = string(v)\n\tcase json.RawMessage:\n\t\tjsonStr = string(v)\n\tdefault:\n\t\treturn \"\", fmt.Errorf(\"metadata must be string, []byte, or json.RawMessage, got %T\", value)\n\t}\n\n\t// Validate that it's valid JSON\n\tif !json.Valid([]byte(jsonStr)) {\n\t\treturn \"\", fmt.Errorf(\"metadata is not valid JSON\")\n\t}\n\n\treturn jsonStr, nil\n}\n\n// MetadataFieldType defines the type of a metadata field for schema validation.\ntype MetadataFieldType string\n\nconst (\n\tMetadataFieldString MetadataFieldType = \"string\"\n\tMetadataFieldInt    MetadataFieldType = \"int\"\n\tMetadataFieldFloat  MetadataFieldType = \"float\"\n\tMetadataFieldBool   MetadataFieldType = \"bool\"\n\tMetadataFieldEnum   MetadataFieldType = \"enum\"\n)\n\n// MetadataFieldSchema defines validation rules for a single metadata field.\ntype MetadataFieldSchema struct {","sourceCodeStart":14,"sourceCodeEnd":50,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/metadata.go#L14-L50","documentation":"The metadata value was an accepted Go type (string, []byte, or json.RawMessage) but its content failed json.Valid — it is not syntactically valid JSON. Storage requires metadata to be a JSON document (typically an object) so it can be queried with JSON path expressions.","triggerScenarios":"Calling UpdateIssue with \"metadata\" set to a plain text string like \"my-metadata\" or \"key=value\", truncated JSON, single-quoted pseudo-JSON, or an empty string; also feeding partially-written buffers as []byte.","commonSituations":"Hand-writing metadata strings with unquoted keys or trailing commas; passing shell-arg text through CLI tooling; string concatenation that produced invalid JSON; encoding bugs producing empty or cut-off payloads.","solutions":["Validate the payload locally with json.Valid before calling the API","Marshal Go values with json.Marshal instead of hand-building JSON strings","Fix quoting: keys and string values must use double quotes (`{\"k\": \"v\"}`)","For an empty metadata set, pass \"{}\" rather than \"\"","Parse the string with json.Unmarshal in a test to pin down the syntax error"],"exampleFix":"// before\nupdates := map[string]interface{}{\"metadata\": \"key=value\"}\n// after\nupdates := map[string]interface{}{\"metadata\": `{\"key\":\"value\"}`}","handlingStrategy":"validation","validationCode":"if !json.Valid([]byte(metaStr)) {\n    return fmt.Errorf(\"refusing to update: metadata is not valid JSON\")\n}","typeGuard":"func validJSONObject(s string) bool {\n    if !json.Valid([]byte(s)) { return false }\n    var m map[string]interface{}\n    return json.Unmarshal([]byte(s), &m) == nil\n}","tryCatchPattern":"if err != nil && strings.Contains(err.Error(), \"metadata is not valid JSON\") {\n    var syntaxErr *json.SyntaxError\n    if errors.As(err, &syntaxErr) { /* locate offset */ }\n    // Re-marshal from the source value instead of passing the raw string.\n    b, merr := json.Marshal(sourceValue)\n    if merr != nil { return merr }\n    updates[\"metadata\"] = json.RawMessage(b)\n}","preventionTips":["Validate with json.Valid before every metadata update","Build JSON with json.Marshal/json.MarshalIndent instead of string concatenation","Use \"{}\" for empty metadata instead of \"\"","Test round-trips: json.Unmarshal the string before sending it to storage"],"tags":["go","metadata","json","validation","malformed-json"],"backgroundTag":"invalid-metadata-json","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}