gastownhall/beads · error
metadata must be a JSON object: %w
Error message
metadata must be a JSON object: %w
What it means
githubRepoFromIssue in cmd/bd/gate.go extracts a GitHub repo from an issue's Metadata field, which must be a JSON object. If issue.Metadata is non-empty but fails to unmarshal into map[string]json.RawMessage, the error is wrapped as 'metadata must be a JSON object: %w'. Empty or null metadata returns ("", nil) silently, so this error only fires on present-but-malformed metadata.
Source
Thrown at cmd/bd/gate.go:862
}
return true
}
// githubRepoFromIssue returns a validated [HOST/]OWNER/REPO value from metadata.repo.
// A missing repo key, or metadata without a repo key at all, means the current
// Git repository should be used. An explicit `"repo":null` or a non-string
// repo value is rejected as malformed rather than silently falling back to
// the current repository - the docs promise malformed values are rejected,
// and a silent fallback here is the dangerous direction (it can point a
// cross-repo check at the wrong repository instead of failing loudly).
func githubRepoFromIssue(issue *types.Issue) (string, error) {
if issue == nil || len(issue.Metadata) == 0 || string(issue.Metadata) == "null" {
return "", nil
}
var raw map[string]json.RawMessage
if err := json.Unmarshal(issue.Metadata, &raw); err != nil {
return "", fmt.Errorf("metadata must be a JSON object: %w", err)
}
repoRaw, hasRepo := raw["repo"]
if !hasRepo {
return "", nil
}
var repoValue interface{}
if err := json.Unmarshal(repoRaw, &repoValue); err != nil {
return "", fmt.Errorf("metadata.repo: %w", err)
}
if repoValue == nil {
return "", fmt.Errorf("metadata.repo must not be null")
}
repo, ok := repoValue.(string)
if !ok {
return "", fmt.Errorf("metadata.repo must be a string, got %T", repoValue)
}
if repo == "" {View on GitHub (pinned to 71377f2769)
Solutions
- Inspect the issue metadata (bd show <id> / export) and fix it to be a valid JSON object containing a "repo" key.
- If metadata was double-encoded (a JSON string containing JSON), decode it once so the field holds an actual object.
- Restore correct metadata via bd update or by re-running the workflow that sets repo metadata.
- Check the wrapped cause for the exact JSON syntax error if the metadata appears valid at a glance.
Example fix
// before
"metadata": "{\"repo\": \"owner/name\"}" // double-encoded string
// after
"metadata": {"repo": "owner/name"} // actual JSON object Defensive patterns
Strategy: type-guard
Validate before calling
// before relying on gate GitHub metadata
var m map[string]json.RawMessage
if err := json.Unmarshal(issue.Metadata, &m); err != nil || m["repo"] == nil {
return errors.New("issue metadata is not an object with a repo key")
} Type guard
// Go
func hasRepoMetadata(md json.RawMessage) bool {
var m map[string]json.RawMessage
return json.Unmarshal(md, &m) == nil && m["repo"] != nil
} Try / catch
if repo, err := githubRepoFromIssue(issue); err != nil {
if strings.Contains(err.Error(), "metadata must be a JSON object") {
// repair or clear the issue metadata before retrying the gate
}
} Prevention
- Store issue metadata as a JSON object, never a double-encoded string.
- Validate metadata JSON after manual edits or migrations.
- Use bd update commands rather than raw DB edits to change metadata.
- Pin consistent bd versions across tools that write issue metadata.
When it happens
Trigger: Calling gate checks (checkGHRun, checkGHPR, matchGatesToRuns via repoMetadataForGate) on an issue whose Metadata is present but not a JSON object — e.g. a JSON array, string, number, or corrupted bytes.
Common situations: Metadata written by older bd versions or external tools in a different shape; manual edits to issue metadata corrupting the JSON; metadata stored as a quoted JSON string (double-encoded) rather than an object; partial writes leaving truncated JSON.
Related errors
- ExternalDoltConfig: must set Socket or (Host, Port)
- metadata.repo: %w
- metadata.repo must not be null
- metadata.repo must be a string, got %T
- parse gh output: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/cd80103c82ad9ad3.
Report an issue: GitHub.