gastownhall/beads · error
metadata.repo must be a string, got %T
Error message
metadata.repo must be a string, got %T
What it means
githubRepoFromIssue requires the decoded `repo` metadata value to be a JSON string. If it is any other JSON type (number, bool, array, object), the type assertion to string fails and the function errors with the Go type of the offending value (e.g. got float64, got []interface {}).
Source
Thrown at cmd/bd/gate.go:878
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 == "" {
return "", fmt.Errorf("repo %q contains an empty path component", repo)
}
for _, char := range part {
if (char >= 'a' && char <= 'z') || (char >= 'A' && char <= 'Z') ||
(char >= '0' && char <= '9') || char == '-' || char == '_' || char == '.' {
continue
}View on GitHub (pinned to 71377f2769)
Solutions
- Correct the stored value to a string: `"repo": "owner/repo"` or `"host/owner/repo"`.
- If a non-string was intentional (e.g. an ID), move it to a different metadata key and keep `repo` string-only.
- Fix the writer producing metadata so it serializes repo as a quoted JSON string.
- Re-run the gate check (`bd doctor` gate flow) after fixing metadata to confirm resolution succeeds.
Example fix
// before
{"repo": 12345}
// after
{"repo": "gastownhall/beads"} Defensive patterns
Strategy: type-guard
Validate before calling
var v interface{}
if err := json.Unmarshal(md["repo"], &v); err == nil {
if _, isStr := v.(string); !isStr {
return errors.New("metadata.repo must be a JSON string")
}
} Type guard
func repoIsString(md map[string][]byte) (string, bool) {
var v interface{}
if json.Unmarshal(md["repo"], &v) != nil { return "", false }
s, ok := v.(string)
return s, ok
} Prevention
- Always serialize repo as a quoted string when writing metadata.
- Add a schema check that validates metadata value types on issue creation/update.
- Watch for double-encoding: unmarshal-then-remarshal when copying metadata between systems.
When it happens
Trigger: Issue metadata contains e.g. `"repo": 123`, `"repo": true`, or `"repo": ["owner","repo"]`; githubRepoFromIssue is called during repoMetadataForGate or GH gate checks and the string type assertion `repoValue.(string)` fails.
Common situations: Scripts writing YAML/JSON booleans or numbers into metadata; double-encoding bugs where a value was unquoted; bulk-import tooling mapping fields incorrectly.
Related errors
- metadata must be string, []byte, or json.RawMessage, got %T
- ExternalDoltConfig: must set Socket or (Host, Port)
- metadata must be a JSON object: %w
- metadata.repo: %w
- metadata.repo must not be null
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/64e2f02a004be8d7.
Report an issue: GitHub.