gastownhall/beads · error · storage.ErrValidation
%w: count edges type %d is not a usable dependency type (non
Error message
%w: count edges type %d is not a usable dependency type (non-empty, max %d chars)
What it means
ValidateEdgeCountRequest rejects an EdgeCountRequest whose Types slice contains a dependency type that fails types.DependencyType.IsValid() — empty or longer than types.MaxDependencyTypeLen. An unusable type would act as a filter that silently matches nothing, so it is refused up front. The error wraps storage.ErrValidation.
Source
Thrown at internal/storage/issueops/edge_counts.go:56
case "":
return fmt.Errorf("%w: count edges requires a direction (%q or %q)",
storage.ErrValidation, publicops.EdgeDirectionOut, publicops.EdgeDirectionIn)
default:
return fmt.Errorf("%w: count edges direction %q is not %q or %q",
storage.ErrValidation, request.Direction, publicops.EdgeDirectionOut, publicops.EdgeDirectionIn)
}
if request.Status != "" && request.Direction != publicops.EdgeDirectionIn {
return fmt.Errorf("%w: count edges status %q needs direction %q: an outbound edge's far end may be a row this database does not hold",
storage.ErrValidation, request.Status, publicops.EdgeDirectionIn)
}
for i, id := range request.IDs {
if id == "" {
return fmt.Errorf("%w: count edges id %d is empty", storage.ErrValidation, i)
}
}
for i, depType := range request.Types {
if !depType.IsValid() {
return fmt.Errorf("%w: count edges type %d is not a usable dependency type (non-empty, max %d chars)",
storage.ErrValidation, i, types.MaxDependencyTypeLen)
}
}
return nil
}
// FinishEdgeCount assembles the per-anchor answer from the two things every
// implementation reads: which anchors exist, and the edge tallies keyed by
// anchor.
//
// It is a pure function beside the body for the reason the checklist gives: the
// parts that decide what the answer MEANS are pinned in milliseconds without a
// database, and the conformance contract is left to assert what only a real
// backend can show. What it decides here is the whole of the missing-anchor
// rule — a missing anchor counts 0 whatever rows are keyed to it, and a present
// anchor with no matching edges counts 0 too, which are the two facts a caller
// tells apart by Missing and by nothing else.
func FinishEdgeCount(anchors []string, present map[string]struct{}, tallies map[string]int64) publicops.EdgeCountResult {View on GitHub (pinned to 71377f2769)
Solutions
- Validate each type with types.DependencyType.IsValid() before building the request and drop/repair bad entries.
- Normalize input: strings.TrimSpace and enforce the MaxDependencyTypeLen limit at the boundary.
- Use the predefined dependency-type constants (e.g. types.DepBlocks, types.DepRelated) instead of raw strings.
- If a version change renamed types, update the callers/config to the current names.
Example fix
// before
req := publicops.EdgeCountRequest{IDs: ids, Direction: "in", Types: []types.DependencyType{userType}}
// after
userType = types.DependencyType(strings.TrimSpace(string(userType)))
if userType != "" && userType.IsValid() {
req := publicops.EdgeCountRequest{IDs: ids, Direction: "in", Types: []types.DependencyType{userType}}
} Defensive patterns
Strategy: validation
Validate before calling
func validTypes(ts []types.DependencyType) bool {
for _, t := range ts { if !t.IsValid() { return false } }
return true
} Type guard
func filterValidTypes(ts []types.DependencyType) []types.DependencyType {
return slices.DeleteFunc(slices.Clone(ts), func(t types.DependencyType) bool { return !t.IsValid() })
} Try / catch
if err := ValidateEdgeCountRequest(req); err != nil {
if errors.Is(err, storage.ErrValidation) && strings.Contains(err.Error(), "dependency type") {
// sanitize types and rebuild the request
}
} Prevention
- Validate each type with DependencyType.IsValid() before building requests
- TrimSpace user-supplied type strings
- Use exported dependency-type constants, not raw strings
- Re-check type names after beads upgrades
When it happens
Trigger: CountEdges / ExecuteEdgeCount called with Types: []types.DependencyType{""} or a type string exceeding MaxDependencyTypeLen; constructing a type via types.DependencyType(rawUserInput) without validation.
Common situations: Free-form user input passed through as a dependency type; a typo like "relates-to " (trailing space inflating length); config or flags supplying a type renamed in a newer beads version; truncation or copying adding whitespace.
Related errors
- edge %d: invalid dependency type %q
- %w: add dependencies edge %d requires a dependency type (max
- %w: count edges status %q needs direction %q: an outbound ed
- %w: count edges id %d is empty
- %w: read edges type %d is not a usable dependency type (non-
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/c4689de8eac610e1.
Report an issue: GitHub.