gastownhall/beads · error
metadata schema violation: %s
Error message
metadata schema violation: %s
What it means
Issue metadata was rejected by the configured metadata schema. When metadata validation mode is 'enforce' (not 'warn'/'none') and a metadata schema is defined in config, any metadata not conforming (wrong type, missing required field, disallowed enum value, out of min/max range) makes the write fail with the first violation reported.
Source
Thrown at internal/storage/issueops/helpers.go:449
schemaCfg := storage.MetadataSchemaConfig{
Mode: mode,
Fields: fields,
}
errs := storage.ValidateMetadataSchema(metadata, schemaCfg)
if len(errs) == 0 {
return nil
}
if mode == "warn" {
for _, e := range errs {
fmt.Fprintf(os.Stderr, "warning: %s\n", e.Error())
}
return nil
}
return fmt.Errorf("metadata schema violation: %s", errs[0].Error())
}
// ParseFieldSchema converts a raw config map into a MetadataFieldSchema.
func ParseFieldSchema(m map[string]interface{}) storage.MetadataFieldSchema {
schema := storage.MetadataFieldSchema{}
if t, ok := m["type"].(string); ok {
schema.Type = storage.MetadataFieldType(t)
}
if req, ok := m["required"].(bool); ok {
schema.Required = req
}
if vals, ok := m["values"]; ok {
switch v := vals.(type) {
case []interface{}:
for _, item := range v {
if s, ok := item.(string); ok {View on GitHub (pinned to 71377f2769)
Solutions
- Fix the metadata payload to satisfy the schema (correct types, include required fields, use allowed values) — the message names the first violation.
- If the violation is intentional during migration, set metadata validation mode to 'warn' in config.yaml until callers are updated.
- Update the schema in config.yaml if the new metadata shape is the desired contract.
- Run validation locally before writing: construct the same schema config and call storage.ValidateMetadataSchema on your metadata JSON to list all violations.
Example fix
// before
metadata := map[string]interface{}{"priority": "high", "owner": "alice"} // priority must be number, owner required? schema says team required
// after
metadata := map[string]interface{}{"priority": 2, "owner": "alice", "team": "core"}
raw, _ := json.Marshal(metadata)
if err := storage.ValidateMetadataSchema(raw, schemaCfg); len(errs) > 0 { fix(errs) } Defensive patterns
Strategy: validation
Validate before calling
func validateBeforeWrite(metadata map[string]interface{}) error {
raw, _ := json.Marshal(metadata)
fields := loadSchemaFieldsFromConfig() // same source bd reads
cfg := storage.MetadataSchemaConfig{Mode: "error", Fields: fields}
errs := storage.ValidateMetadataSchema(raw, cfg)
if len(errs) > 0 { return errors.New(errs[0].Error()) }
return nil
} Try / catch
if err := storage.ValidateMetadataIfConfigured(rawMeta); err != nil {
var retryable bool
if strings.HasPrefix(err.Error(), "metadata schema violation:") {
// fix payload per the reported violation, then retry
return fmt.Errorf("fix metadata: %w", err)
}
return err
} Prevention
- Validate metadata payloads against the schema in CI before bd create/update.
- When tightening a schema, first run mode 'warn', migrate all writers, then switch to enforce.
- Include all required fields and use schema-declared enum values in automation scripts.
- Match JSON types exactly to the schema (numbers as numbers, not strings).
When it happens
Trigger: Calling bd create/update (ApplyMetadataPatch, PrepareIssueForInsert, metadata merge ops) with issue metadata that violates the schema declared under metadata schema fields in config.yaml, while metadata-validation mode is set to enforce/error.
Common situations: CI automation writing metadata keys with wrong types (string vs number); a teammate tightened the schema and old scripts now fail; required field added to schema but not supplied; enum value renamed in config but still sent by clients.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
- metadata validation failed for issue %s: %w
- ExternalDoltConfig: must set Socket or (Host, Port)
- server: NewDoltServer: doltBinExec is required
- server: NewDoltServer: rootDir is required
- server: NewDoltServer: configPath is required
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/d44304d50ec0f244.
Report an issue: GitHub.