gastownhall/beads · error
metadata.repo: %w
Error message
metadata.repo: %w
What it means
githubRepoFromIssue parses the `repo` metadata key stored on a gate-bearing issue. When the raw JSON value exists but cannot be unmarshaled (malformed JSON stored in metadata), the function wraps the json.Unmarshal error as "metadata.repo: %w" and aborts repo resolution for the gate checks.
Source
Thrown at cmd/bd/gate.go:871
// 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 == "" {
return "", nil
}
parts := strings.Split(repo, "/")
if len(parts) != 2 && len(parts) != 3 {
return "", fmt.Errorf("repo %q must use OWNER/REPO or HOST/OWNER/REPO", repo)
}
for _, part := range parts {
if part == "" {View on GitHub (pinned to 71377f2769)
Solutions
- Inspect the issue metadata with `bd show <id>` (or query Dolt) and re-write the `repo` value as a valid JSON string, e.g. `"owner/repo"`.
- Remove the malformed `repo` key entirely so githubRepoFromIssue returns "" (no repo) instead of failing.
- Re-set the field via the supported CLI (bd update / metadata command) rather than editing raw JSON by hand.
- Check for schema drift: if issues were migrated from an older format, re-export/normalize metadata.
Example fix
// before (malformed stored value)
metadata: {"repo": owner/repo}
// after
metadata: {"repo": "owner/repo"} Defensive patterns
Strategy: validation
Validate before calling
// before running gate checks, parse the stored metadata yourself
raw, ok := issue.Metadata["repo"]
if ok {
var v interface{}
if err := json.Unmarshal(raw, &v); err != nil {
return fmt.Errorf("issue %s has malformed metadata.repo: %w", issue.ID, err)
}
} Type guard
func hasValidRepoMetadata(md map[string][]byte) bool {
raw, ok := md["repo"]
if !ok { return true } // absent is fine
var v interface{}
return json.Unmarshal(raw, &v) == nil
} Prevention
- Write metadata only through bd CLI commands, never by hand-editing JSON/Dolt rows.
- Validate issue metadata with bd lint/doctor before running gate checks in CI.
- When migrating issue data, round-trip parse every metadata field first.
When it happens
Trigger: An issue's metadata map contains a `repo` key whose value is stored as an invalid JSON fragment (e.g. truncated or double-encoded bytes), so json.Unmarshal fails when githubRepoFromIssue reads it during gate matching (repoMetadataForGate / checkGH* / matchGatesToRuns).
Common situations: Corrupted or hand-edited Dolt/metadata rows; scripts writing metadata with improper JSON escaping; older tool versions that wrote the repo value in a non-JSON-compatible format.
Related errors
- ExternalDoltConfig: must set Socket or (Host, Port)
- metadata.repo must not be null
- loading config for gate resolution: %w
- invalid metadata: %w
- invalid metadata: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/09aee3cd138f7e20.
Report an issue: GitHub.