{"record":{"id":"09aee3cd138f7e20","repo":"gastownhall/beads","slug":"metadata-repo-w","errorCode":null,"errorMessage":"metadata.repo: %w","messagePattern":"metadata\\.repo: %w","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cmd/bd/gate.go","lineNumber":871,"sourceCode":"// and a silent fallback here is the dangerous direction (it can point a\n// cross-repo check at the wrong repository instead of failing loudly).\nfunc githubRepoFromIssue(issue *types.Issue) (string, error) {\n\tif issue == nil || len(issue.Metadata) == 0 || string(issue.Metadata) == \"null\" {\n\t\treturn \"\", nil\n\t}\n\n\tvar raw map[string]json.RawMessage\n\tif err := json.Unmarshal(issue.Metadata, &raw); err != nil {\n\t\treturn \"\", fmt.Errorf(\"metadata must be a JSON object: %w\", err)\n\t}\n\trepoRaw, hasRepo := raw[\"repo\"]\n\tif !hasRepo {\n\t\treturn \"\", nil\n\t}\n\n\tvar repoValue interface{}\n\tif err := json.Unmarshal(repoRaw, &repoValue); err != nil {\n\t\treturn \"\", fmt.Errorf(\"metadata.repo: %w\", err)\n\t}\n\tif repoValue == nil {\n\t\treturn \"\", fmt.Errorf(\"metadata.repo must not be null\")\n\t}\n\trepo, ok := repoValue.(string)\n\tif !ok {\n\t\treturn \"\", fmt.Errorf(\"metadata.repo must be a string, got %T\", repoValue)\n\t}\n\tif repo == \"\" {\n\t\treturn \"\", nil\n\t}\n\n\tparts := strings.Split(repo, \"/\")\n\tif len(parts) != 2 && len(parts) != 3 {\n\t\treturn \"\", fmt.Errorf(\"repo %q must use OWNER/REPO or HOST/OWNER/REPO\", repo)\n\t}\n\tfor _, part := range parts {\n\t\tif part == \"\" {","sourceCodeStart":853,"sourceCodeEnd":889,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/cmd/bd/gate.go#L853-L889","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","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."],"exampleFix":"// before (malformed stored value)\nmetadata: {\"repo\": owner/repo}\n// after\nmetadata: {\"repo\": \"owner/repo\"}","handlingStrategy":"validation","validationCode":"// before running gate checks, parse the stored metadata yourself\nraw, ok := issue.Metadata[\"repo\"]\nif ok {\n    var v interface{}\n    if err := json.Unmarshal(raw, &v); err != nil {\n        return fmt.Errorf(\"issue %s has malformed metadata.repo: %w\", issue.ID, err)\n    }\n}","typeGuard":"func hasValidRepoMetadata(md map[string][]byte) bool {\n    raw, ok := md[\"repo\"]\n    if !ok { return true } // absent is fine\n    var v interface{}\n    return json.Unmarshal(raw, &v) == nil\n}","tryCatchPattern":null,"preventionTips":["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."],"tags":["json","metadata","validation"],"backgroundTag":"invalid-json-metadata","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}