gastownhall/beads · error · issueops.ErrValidation
%w: apply batch item %d: %s must name a key or an id
Error message
%w: apply batch item %d: %s must name a key or an id
What it means
This error is thrown by validateApplyRef when an item in an apply batch references an issue (as a dependency endpoint or target) without naming it: both ref.Key and ref.ID are empty. The batch applier needs exactly one identifier to resolve the ref, so it rejects the item at plan time with a wrapped issueops.ErrValidation.
Source
Thrown at internal/storage/batch_apply.go:324
}
if ref.Key == "" {
return nil
}
declaredAt, ok := keyIndex[ref.Key]
if !ok {
return &issueops.RefError{Index: index, Member: member, Key: ref.Key}
}
if declaredAt >= index {
return &issueops.RefError{Index: index, Member: member, Key: ref.Key, DeclaredLater: true}
}
return nil
}
// validateApplyRef checks the exactly-one rule every ref answers to.
func validateApplyRef(ref issueops.Ref, index int, member string) error {
switch {
case ref.Key == "" && ref.ID == "":
return fmt.Errorf("%w: apply batch item %d: %s must name a key or an id", issueops.ErrValidation, index, member)
case ref.Key != "" && ref.ID != "":
return fmt.Errorf("%w: apply batch item %d: %s names both key %q and id %q; exactly one",
issueops.ErrValidation, index, member, ref.Key, ref.ID)
}
return nil
}
// applyTouchKeyRef renders a ref as the address the touched set is keyed by.
// The two namespaces are kept apart so a key and an id that happen to read the
// same string are not confused for one row.
func applyTouchKeyRef(ref issueops.Ref) string {
if ref.Key != "" {
return "key:" + ref.Key
}
return "id:" + ref.ID
}
// applyRefLabel renders a ref for a message.View on GitHub (pinned to 71377f2769)
Solutions
- Populate exactly one of ref.Key or ref.ID on every batch item before calling the apply API
- Validate all refs client-side before building the batch
- Check the payload/JSON actually carries the key or id field for each item
Example fix
// before
refs := []issueops.Ref{{}}
// after
refs := []issueops.Ref{{Key: "beads-42"}} Defensive patterns
Strategy: validation
Validate before calling
func validateRef(r issueops.Ref, i int, member string) error {
if r.Key == "" && r.ID == "" {
return fmt.Errorf("item %d: %s needs a key or id", i, member)
}
return nil
} Type guard
func refNamed(r issueops.Ref) bool { return r.Key != "" || r.ID != "" } Prevention
- Always populate Key or ID when building batch items
- Validate the whole batch before submitting
- Unmarshal into Ref structs with required-field checks
When it happens
Trigger: Calling a batch apply API (planApplyBatchCreate path, or a dep/target ref validated via validateApplyTargetRef) with a Ref struct where both Key and ID are the empty string.
Common situations: Constructing batch items programmatically from structs where the ref field was never populated; deserializing JSON payloads that omit the key/id fields; copying a Ref after clearing fields; passing a zero-value Ref.
Related errors
- no store is open for this workspace
- not found
- db: ChildCounterSQLRepository.NextChildID: parentID must not
- db: DependencySQLRepository.Insert: dep must not be nil
- db: DependencySQLRepository.Insert: IssueID must not be empt
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/b714dd44ddcb577c.
Report an issue: GitHub.