{"record":{"id":"dfb690dae51f4a88","repo":"gastownhall/beads","slug":"direction-q-must-be-one-of-q-q-q","errorCode":null,"errorMessage":"direction %q must be one of %q, %q, %q","messagePattern":"direction %q must be one of %q, %q, %q","errorType":"validation","errorClass":"publicops.ErrValidation","httpStatus":null,"severity":"error","filePath":"internal/storage/issueops/tree_walk.go","lineNumber":36,"sourceCode":"// needs a transaction because the root probe, the recursion and the hydration\n// must see one database state, and for a `both` walk that covers BOTH\n// directions.\n\n// ValidateWalkTreeRequest checks a walk request against the vocabulary\n// issueops.WalkTreeRequest documents and returns the normalized direction. It is\n// pure and shared so that all three backends refuse in the same words.\nfunc ValidateWalkTreeRequest(req publicops.WalkTreeRequest) (publicops.TreeDirection, error) {\n\tif req.RootID == \"\" {\n\t\treturn \"\", fmt.Errorf(\"%w: root id must not be empty\", publicops.ErrValidation)\n\t}\n\tdirection := req.Direction\n\tif direction == \"\" {\n\t\tdirection = publicops.TreeDown\n\t}\n\tswitch direction {\n\tcase publicops.TreeDown, publicops.TreeUp, publicops.TreeBoth:\n\tdefault:\n\t\treturn \"\", fmt.Errorf(\"%w: direction %q must be one of %q, %q, %q\",\n\t\t\tpublicops.ErrValidation, req.Direction,\n\t\t\tpublicops.TreeDown, publicops.TreeUp, publicops.TreeBoth)\n\t}\n\tif req.MaxDepth < 1 {\n\t\treturn \"\", fmt.Errorf(\"%w: max depth must be at least 1, got %d\", publicops.ErrValidation, req.MaxDepth)\n\t}\n\tif req.MaxRows < 0 {\n\t\treturn \"\", fmt.Errorf(\"%w: max rows must not be negative, got %d\", publicops.ErrValidation, req.MaxRows)\n\t}\n\treturn direction, nil\n}\n\n// PruneTreeByStatus keeps every node carrying status, plus the ancestor chain of\n// each survivor, in the walk order the nodes arrived in.\n//\n// KEEPING THE ANCESTORS IS WHAT MAKES THE ANSWER STILL A TREE. A bare filter\n// would return nodes whose ParentID names something absent from the answer, and\n// every renderer that rebuilds the shape from Depth and ParentID would then draw","sourceCodeStart":18,"sourceCodeEnd":54,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/issueops/tree_walk.go#L18-L54","documentation":"ValidateWalkTreeRequest rejects a WalkDependencyTreeRequest whose Direction field is not one of the three supported traversal directions (down, up, both). The library throws this wrapped in publicops.ErrValidation because the caller supplied an unrecognized direction string, likely a typo or a value copied from a different API. An empty direction is silently defaulted to TreeDown, so only non-empty invalid values reach this error.","triggerScenarios":"Calling WalkDependencyTreeInTx (directly or via WalkDependencyTree) with req.Direction set to any string other than publicops.TreeDown, TreeUp, or TreeBoth, e.g. \"downward\", \"children\", \"D\", or a stale constant from an older SDK version.","commonSituations":"Hand-building the request struct instead of using helpers; renaming between API versions where direction constants changed; user-supplied CLI input passed straight into Direction without mapping.","solutions":["Set req.Direction to one of publicops.TreeDown, publicops.TreeUp, or publicops.TreeBoth.","Leave req.Direction empty (\"\") to accept the default (TreeDown).","Map/normalize user input against the three constants before constructing the request.","Check that you are not importing similarly-named constants from a different package or an outdated version."],"exampleFix":"// before\nreq := publicops.WalkDependencyTreeRequest{IssueID: id, Direction: \"down\"}\n// after\nreq := publicops.WalkDependencyTreeRequest{IssueID: id, Direction: publicops.TreeDown}","handlingStrategy":"validation","validationCode":"func validDirection(d string) bool {\n\treturn d == \"\" || d == publicops.TreeDown || d == publicops.TreeUp || d == publicops.TreeBoth\n}\nif !validDirection(req.Direction) {\n\treturn fmt.Errorf(\"direction %q not supported\", req.Direction)\n}","typeGuard":null,"tryCatchPattern":"if err := walk(ctx, req); errors.Is(err, publicops.ErrValidation) {\n\t// fix request fields; do not retry\n}","preventionTips":["Always use the exported TreeDown/TreeUp/TreeBoth constants rather than string literals.","Validate CLI/JSON input against the constant set before building the request.","Rely on the empty-string default instead of inventing your own \"default\" value."],"tags":["validation","dependency-tree","bad-request"],"backgroundTag":"invalid-enum-value","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}