{"record":{"id":"d40c08f6e3eae6bd","repo":"gastownhall/beads","slug":"w-read-edges-type-d-is-not-a-usable-dependency","errorCode":null,"errorMessage":"%w: read edges type %d is not a usable dependency type (non-empty, max %d chars)","messagePattern":"%w: read edges type (.+?) is not a usable dependency type \\(non-empty, max (.+?) chars\\)","errorType":"validation","errorClass":"storage.ErrValidation","httpStatus":null,"severity":"error","filePath":"internal/storage/issueops/edges.go","lineNumber":27,"sourceCode":"\t\"github.com/steveyegge/beads/internal/storage\"\n\t\"github.com/steveyegge/beads/internal/types\"\n\tpublicops \"github.com/steveyegge/beads/issueops\"\n)\n\n// ValidateEdgeReadRequest applies the request rules every EdgeReader\n// implementation shares. Both tell a caller's mistake from a legitimately empty\n// answer: an empty ID entry names nothing, and an unusable dependency type would\n// become a filter that silently matches nothing. An empty ID SLICE is neither —\n// it asks about no anchors and gets none back.\nfunc ValidateEdgeReadRequest(request publicops.EdgeReadRequest) error {\n\tfor i, id := range request.IDs {\n\t\tif id == \"\" {\n\t\t\treturn fmt.Errorf(\"%w: read edges id %d is empty\", storage.ErrValidation, i)\n\t\t}\n\t}\n\tfor i, depType := range request.Types {\n\t\tif !depType.IsValid() {\n\t\t\treturn fmt.Errorf(\"%w: read edges type %d is not a usable dependency type (non-empty, max %d chars)\",\n\t\t\t\tstorage.ErrValidation, i, types.MaxDependencyTypeLen)\n\t\t}\n\t}\n\treturn nil\n}\n\n// EdgeReadAnchors is the de-duplicated anchor list a read runs against: the\n// request's ids with repeats collapsed onto their first mention.\n//\n// It is shared rather than a loop in each implementation because the\n// de-duplication decides the SHAPE of the answer — one entry per distinct id, in\n// first-mention order. BlockingAnnotator makes the same promise over the same\n// shape of request (blocking_annotation.go) and reaches it here too.\nfunc EdgeReadAnchors(ids []string) []string {\n\tseen := make(map[string]struct{}, len(ids))\n\tout := make([]string, 0, len(ids))\n\tfor _, id := range ids {\n\t\tif _, dup := seen[id]; dup {","sourceCodeStart":9,"sourceCodeEnd":45,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/issueops/edges.go#L9-L45","documentation":"ValidateEdgeReadRequest rejects an EdgeReadRequest whose Types slice contains a dependency type that fails types.DependencyType.IsValid() — empty or exceeding types.MaxDependencyTypeLen. Such a type would act as a filter silently matching no edges, so it is refused instead. The error wraps storage.ErrValidation.","triggerScenarios":"ReadEdges / ExecuteEdgeRead called with Types containing \"\" or an over-long string; types.DependencyType built from raw user input or config values without validation.","commonSituations":"Typo'd or renamed dependency types in flags/config; a type with trailing whitespace exceeding the length limit; older code using a type name removed or shortened in a newer beads release.","solutions":["Call types.DependencyType.IsValid() on each filter before building the request.","Trim whitespace and enforce MaxDependencyTypeLen at the input boundary.","Use the exported dependency-type constants instead of ad-hoc strings.","Update callers to current type names after upgrades."],"exampleFix":"// before\nreq := publicops.EdgeReadRequest{IDs: ids, Types: []types.DependencyType{t}}\n// after\nif !t.IsValid() { return fmt.Errorf(\"bad dependency type %q\", t) }\nreq := publicops.EdgeReadRequest{IDs: ids, Types: []types.DependencyType{t}}","handlingStrategy":"validation","validationCode":"func validTypes(ts []types.DependencyType) bool {\n\tfor _, t := range ts { if !t.IsValid() { return false } }\n\treturn true\n}","typeGuard":"func filterValidTypes(ts []types.DependencyType) []types.DependencyType {\n\treturn slices.DeleteFunc(slices.Clone(ts), func(t types.DependencyType) bool { return !t.IsValid() })\n}","tryCatchPattern":"if err := ValidateEdgeReadRequest(req); err != nil {\n\tif errors.Is(err, storage.ErrValidation) && strings.Contains(err.Error(), \"dependency type\") {\n\t\treq.Types = filterValidTypes(req.Types)\n\t}\n}","preventionTips":["Run DependencyType.IsValid() on filters before the call","Trim and length-check type strings at input","Prefer exported type constants","Update configs after type renames between versions"],"tags":["validation","dependency-type","edge-read"],"backgroundTag":"invalid-request-validation","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}