gastownhall/beads · error
metadata validation failed for issue %s: %w
Error message
metadata validation failed for issue %s: %w
What it means
PrepareIssueForInsert validates the issue's optional Metadata field against the configured metadata schema via ValidateMetadataIfConfigured before insert, wrapping failures as "metadata validation failed for issue %s: %w" with the issue ID. Metadata validation only runs when a schema is configured; unstructured metadata passes untouched when none is set.
Source
Thrown at internal/storage/issueops/create.go:531
affectedIssues, affectedWisps, err = AffectedByDepChangeInTx(ctx, tx, dependency.source, dependency.target, dependency.depType)
}
if err != nil {
return nil, nil, fmt.Errorf("affected by created dependency %s -> %s: %w", dependency.source, dependency.target, err)
}
for _, id := range affectedIssues {
add(id, false)
}
for _, id := range affectedWisps {
add(id, true)
}
}
return issueIDs, wispIDs, nil
}
// PrepareIssueForInsert normalizes timestamps, validates, and computes the content hash.
func PrepareIssueForInsert(issue *types.Issue, customStatuses, customTypes []string) error {
if err := ValidateMetadataIfConfigured(issue.Metadata); err != nil {
return fmt.Errorf("metadata validation failed for issue %s: %w", issue.ID, err)
}
// Normalize timestamps to UTC, defaulting to now.
now := time.Now().UTC()
if issue.CreatedAt.IsZero() {
issue.CreatedAt = now
} else {
issue.CreatedAt = issue.CreatedAt.UTC()
}
if issue.UpdatedAt.IsZero() {
issue.UpdatedAt = now
} else {
issue.UpdatedAt = issue.UpdatedAt.UTC()
}
// Ensure closed issues have a closed_at timestamp.
if issue.Status == types.StatusClosed && issue.ClosedAt == nil {
maxTime := issue.CreatedAtView on GitHub (pinned to 71377f2769)
Solutions
- Read the wrapped validation error to see which metadata key/rule failed and correct the issue's Metadata map before insert.
- Run the same validation client-side (ValidateMetadataIfConfigured) before submitting so the failure surfaces at the call site.
- If legacy issues legitimately lack new fields, relax the configured schema (make fields optional) or backfill the metadata.
Example fix
// before
issue := &types.Issue{Title: "x", Metadata: map[string]any{"priority": "high"}}
// schema expects integer priority -> validation fails
// after
issue := &types.Issue{Title: "x", Metadata: map[string]any{"priority": 2}}
if err := issueops.ValidateMetadataIfConfigured(issue.Metadata); err != nil {
return fmt.Errorf("fix metadata: %w", err)
} Defensive patterns
Strategy: validation
Validate before calling
if err := issueops.ValidateMetadataIfConfigured(issue.Metadata); err != nil {
return fmt.Errorf("metadata for %s invalid: %w", issue.ID, err)
} Try / catch
if err := store.CreateIssue(ctx, issue); err != nil {
if strings.Contains(err.Error(), "metadata validation failed") {
return fmt.Errorf("reject/repair metadata before retry: %w", err)
}
return err
} Prevention
- Share one metadata-building helper so keys and types are consistent everywhere.
- When introducing a metadata schema, backfill or grandfather existing issues first.
- Match JSON types exactly to the schema (int vs string) in automation that writes metadata.
When it happens
Trigger: Creating/updating an issue (CreateIssueInTxWithResult, PromoteFromEphemeralInTx, PreparePublicCreateRequest) whose Metadata map violates the configured schema: missing required keys, wrong value types, or disallowed fields; importing issues from another repo whose metadata does not match local config.
Common situations: Teams adding a metadata schema to an existing database whose old issues (or import payloads) predate it; automation writing metadata keys with wrong JSON types (string vs number); typo'd metadata keys in scripts.
Related errors
- metadata schema violation: %s
- ExternalDoltConfig: must set Socket or (Host, Port)
- metadata.repo: %w
- metadata.repo must not be null
- invalid repo metadata: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/227024f378204512.
Report an issue: GitHub.