gastownhall/beads · error
metadata is not valid JSON
Error message
metadata is not valid JSON
What it means
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.
Source
Thrown at internal/storage/metadata.go:32
//
// This supports GH#1417: allow UpdateIssue metadata updates via json.RawMessage/[]byte.
func NormalizeMetadataValue(value interface{}) (string, error) {
var jsonStr string
switch v := value.(type) {
case string:
jsonStr = v
case []byte:
jsonStr = string(v)
case json.RawMessage:
jsonStr = string(v)
default:
return "", fmt.Errorf("metadata must be string, []byte, or json.RawMessage, got %T", value)
}
// Validate that it's valid JSON
if !json.Valid([]byte(jsonStr)) {
return "", fmt.Errorf("metadata is not valid JSON")
}
return jsonStr, nil
}
// MetadataFieldType defines the type of a metadata field for schema validation.
type MetadataFieldType string
const (
MetadataFieldString MetadataFieldType = "string"
MetadataFieldInt MetadataFieldType = "int"
MetadataFieldFloat MetadataFieldType = "float"
MetadataFieldBool MetadataFieldType = "bool"
MetadataFieldEnum MetadataFieldType = "enum"
)
// MetadataFieldSchema defines validation rules for a single metadata field.
type MetadataFieldSchema struct {View on GitHub (pinned to 71377f2769)
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
Example fix
// before
updates := map[string]interface{}{"metadata": "key=value"}
// after
updates := map[string]interface{}{"metadata": `{"key":"value"}`} Defensive patterns
Strategy: validation
Validate before calling
if !json.Valid([]byte(metaStr)) {
return fmt.Errorf("refusing to update: metadata is not valid JSON")
} Type guard
func validJSONObject(s string) bool {
if !json.Valid([]byte(s)) { return false }
var m map[string]interface{}
return json.Unmarshal([]byte(s), &m) == nil
} Try / catch
if err != nil && strings.Contains(err.Error(), "metadata is not valid JSON") {
var syntaxErr *json.SyntaxError
if errors.As(err, &syntaxErr) { /* locate offset */ }
// Re-marshal from the source value instead of passing the raw string.
b, merr := json.Marshal(sourceValue)
if merr != nil { return merr }
updates["metadata"] = json.RawMessage(b)
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- ExternalDoltConfig: must set Socket or (Host, Port)
- %w: metadata replacement is not valid JSON
- %w: metadata merge must be a JSON object
- %w: metadata merge: %v
- %w: metadata edits require an object: %v
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/3f8a1edea3946d22.
Report an issue: GitHub.