gastownhall/beads · error · publicops.ErrValidation

max rows must not be negative, got %d

Error message

max rows must not be negative, got %d

What it means

ValidateWalkTreeRequest rejects a negative MaxRows with this ErrValidation-wrapped error. The library throws it because a negative row cap is meaningless for a result-limiting field; use 0 (treated as the library's no-limit/default) or a positive cap.

Source

Thrown at internal/storage/issueops/tree_walk.go:44

	if req.RootID == "" {
		return "", fmt.Errorf("%w: root id must not be empty", publicops.ErrValidation)
	}
	direction := req.Direction
	if direction == "" {
		direction = publicops.TreeDown
	}
	switch direction {
	case publicops.TreeDown, publicops.TreeUp, publicops.TreeBoth:
	default:
		return "", fmt.Errorf("%w: direction %q must be one of %q, %q, %q",
			publicops.ErrValidation, req.Direction,
			publicops.TreeDown, publicops.TreeUp, publicops.TreeBoth)
	}
	if req.MaxDepth < 1 {
		return "", fmt.Errorf("%w: max depth must be at least 1, got %d", publicops.ErrValidation, req.MaxDepth)
	}
	if req.MaxRows < 0 {
		return "", fmt.Errorf("%w: max rows must not be negative, got %d", publicops.ErrValidation, req.MaxRows)
	}
	return direction, nil
}

// PruneTreeByStatus keeps every node carrying status, plus the ancestor chain of
// each survivor, in the walk order the nodes arrived in.
//
// KEEPING THE ANCESTORS IS WHAT MAKES THE ANSWER STILL A TREE. A bare filter
// would return nodes whose ParentID names something absent from the answer, and
// every renderer that rebuilds the shape from Depth and ParentID would then draw
// orphans at the wrong indentation.
//
// A PRUNE THAT MATCHES NOTHING RETURNS NOTHING, root included. The root survives
// only as somebody's ancestor, never for its own sake, so a tree with no
// matching member comes back empty rather than as a lone root — see
// issueops.WalkTreeRequest.Status, which states it as a promise.
func PruneTreeByStatus(nodes []*types.TreeNode, status types.Status) []*types.TreeNode {
	if len(nodes) == 0 {

View on GitHub (pinned to 71377f2769)

Solutions

  1. Set req.MaxRows to 0 to mean unlimited, or a positive integer to cap results.
  2. Clamp computed values: if maxRows < 0 { maxRows = 0 }.
  3. Update code that uses the -1-as-unlimited convention to this library's 0-means-unlimited convention.

Example fix

// before
req.MaxRows = -1 // "unlimited"
// after
req.MaxRows = 0 // 0 means no row limit
Defensive patterns

Strategy: validation

Validate before calling

if req.MaxRows < 0 {
	req.MaxRows = 0
}

Try / catch

if err := walk(ctx, req); errors.Is(err, publicops.ErrValidation) {
	// fix MaxRows; validation errors are not retryable as-is
}

Prevention

When it happens

Trigger: Calling WalkDependencyTreeInTx with req.MaxRows < 0, e.g. -1 used as an "unlimited" sentinel carried over from a different API's convention.

Common situations: Using -1 for "no limit" per another library's convention; computing MaxRows via subtraction that can go negative; misparsed config values.

Related errors


AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30). Data as JSON: /api/errors/a244757451842f49. Report an issue: GitHub.