gastownhall/beads · error
provenance: unknown ref-kind %q
Error message
provenance: unknown ref-kind %q
What it means
If an event carries a RefKind, it must be one of the known ref kinds (git-sha, pr, work-id, transcript, branch); an unrecognized RefKind is rejected with 'provenance: unknown ref-kind %q'. RefKind is a closed vocabulary so downstream tools know how to resolve refs.
Source
Thrown at internal/storage/issueops/provenance.go:65
// before it is recorded: kind, ref_kind (when present), the git-sha ref shape,
// and the reserved source. It never interprets the opaque actor/ref values. It
// is exported so the CLI can fail early with the same rules the store enforces.
func ValidateProvenanceEvent(ev types.ProvenanceEvent) error {
if strings.TrimSpace(ev.IssueID) == "" {
return fmt.Errorf("provenance: issue id is required")
}
if _, ok := knownProvKinds[ev.Kind]; !ok {
return fmt.Errorf("provenance: unknown kind %q", ev.Kind)
}
if strings.TrimSpace(ev.Source) == "" {
return fmt.Errorf("provenance: source is required")
}
if strings.EqualFold(strings.TrimSpace(ev.Source), ReservedProvSource) {
return fmt.Errorf("provenance: source %q is reserved for ingest backfill and cannot be recorded directly", ReservedProvSource)
}
if ev.RefKind != nil {
if _, ok := knownProvRefKinds[*ev.RefKind]; !ok {
return fmt.Errorf("provenance: unknown ref-kind %q", *ev.RefKind)
}
if ev.Ref == nil || *ev.Ref == "" {
return fmt.Errorf("provenance: ref-kind %q requires a ref", *ev.RefKind)
}
if *ev.RefKind == "git-sha" {
if !gitSHARE.MatchString(*ev.Ref) {
return fmt.Errorf("provenance: ref-kind git-sha requires a 40-character lowercase hex ref")
}
}
}
// A ref-less event is keyed by occurred_at for its stable id; without either,
// two distinct events would collapse to the same content-addressed id. Guard
// at the store boundary so every caller (CLI or library) is covered.
if (ev.Ref == nil || *ev.Ref == "") && ev.OccurredAt == nil {
return fmt.Errorf("provenance: event with no ref requires occurred_at (--at) for a stable id")
}
return nil
}View on GitHub (pinned to 71377f2769)
Solutions
- Translate external link types to the supported set: commit SHA -> "git-sha", PR number -> "pr", etc.
- Only set ev.RefKind when you actually have a ref; leave it nil otherwise (note the next check also demands a non-empty Ref for any set RefKind)
- Use string constants mirroring knownProvRefKinds rather than inline literals
- Pre-validate with ValidateProvenanceEvent before opening the transaction
Example fix
// before
evk := "commit"
ev := types.ProvenanceEvent{IssueID: id, Kind: types.ProvCommit, Source: "ci", RefKind: &evk, Ref: &sha}
// after
evk := "git-sha" // must be one of: git-sha, pr, work-id, transcript, branch
ev := types.ProvenanceEvent{IssueID: id, Kind: types.ProvCommit, Source: "ci", RefKind: &evk, Ref: &sha}
if err := issueops.ValidateProvenanceEvent(ev); err != nil {
return err
} Defensive patterns
Strategy: validation
Validate before calling
validRefKinds := map[string]bool{"git-sha": true, "pr": true, "work-id": true, "transcript": true, "branch": true}
if ev.RefKind != nil && !validRefKinds[*ev.RefKind] {
return fmt.Errorf("unsupported ref-kind %q", *ev.RefKind)
}
return issueops.ValidateProvenanceEvent(ev) Type guard
func isKnownRefKind(k *string) bool {
if k == nil { return true }
switch *k {
case "git-sha", "pr", "work-id", "transcript", "branch": return true
}
return false
} Try / catch
if err := issueops.ValidateProvenanceEvent(ev); err != nil {
if strings.Contains(err.Error(), "unknown ref-kind") {
return fmt.Errorf("translate ref-kind %q to git-sha/pr/work-id/transcript/branch", *ev.RefKind)
}
return err
} Prevention
- Define string constants for the five valid ref kinds and use them everywhere
- Translate external link types at your integration boundary (commit -> git-sha)
- Leave RefKind nil when there is no ref — never set an empty-string kind
- Remember ref-kind "git-sha" additionally requires a value matching the git SHA pattern; pre-validate that too
When it happens
Trigger: Recording an event with ev.RefKind set to anything outside {"git-sha","pr","work-id","transcript","branch"} — e.g. "commit", "sha", "url", or the empty string in a non-nil pointer.
Common situations: Mapping external systems' link types (commit, issue URL) directly onto RefKind without translating to the supported set; typo'd ref kinds in scripts; nil-vs-empty confusion producing RefKind="".
Related errors
- provenance: unknown kind %q
- ExternalDoltConfig: TLSCert set without TLSKey
- unknown backend %q (want one of: %s)
- %w: invalid persistence mode %q
- %w: invalid issue type %s
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/59a5f0e4e1467299.
Report an issue: GitHub.