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

  1. 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"`.
  2. Remove the malformed `repo` key entirely so githubRepoFromIssue returns "" (no repo) instead of failing.
  3. Re-set the field via the supported CLI (bd update / metadata command) rather than editing raw JSON by hand.
  4. 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

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


AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30). Data as JSON: /api/errors/09aee3cd138f7e20. Report an issue: GitHub.