gastownhall/beads · error · storage.ErrValidation

%w: remove dependency requires an actor

Error message

%w: remove dependency requires an actor

What it means

ValidateRemoveDependencyRequest rejects a RemoveDependencyRequest whose Actor field is empty, wrapping storage.ErrValidation. Every dependency mutation is attributed to an actor so the change is recorded durably in history; a removal without an actor cannot be audited, so the request is refused before any database work. The %w wrap lets callers match errors.Is(err, storage.ErrValidation).

Source

Thrown at internal/storage/issueops/dependency_editor.go:54

		if edge.IssueID == "" || edge.DependsOnID == "" {
			return fmt.Errorf("%w: add dependencies edge %d requires both endpoints", storage.ErrValidation, i)
		}
		if !edge.Type.IsValid() {
			return fmt.Errorf("%w: add dependencies edge %d requires a dependency type (max %d chars)",
				storage.ErrValidation, i, types.MaxDependencyTypeLen)
		}
		if edge.IssueID == edge.DependsOnID {
			return fmt.Errorf("%w: %s cannot depend on itself", domain.ErrSelfDependency, edge.IssueID)
		}
	}
	return nil
}

// ValidateRemoveDependencyRequest applies the request rules every
// DependencyEditor implementation shares for a removal.
func ValidateRemoveDependencyRequest(request publicops.RemoveDependencyRequest) error {
	if request.Actor == "" {
		return fmt.Errorf("%w: remove dependency requires an actor", storage.ErrValidation)
	}
	if request.IssueID == "" || request.DependsOnID == "" {
		return fmt.Errorf("%w: remove dependency requires both endpoints", storage.ErrValidation)
	}
	return nil
}

// AddDependenciesCommitMessage is the history entry an edge assertion records.
//
// Unlike CloseBatchCommitMessage it is composed from the REQUEST rather than
// the result, and that difference is the contract's: the request is
// all-or-nothing, so what was asked for is exactly what landed or nothing did.
// A batch close has to name what landed because it can skip an id; this cannot.
//
// The two spellings are the two the CLI already wrote — one edge names both
// endpoints, several name their count — because the role is what both `bd dep
// add <a> <b>` and `bd dep add --file` now go through, and `bd dolt log` should
// keep reading the way it did. The count spelling is keyed on the EDGE COUNT

View on GitHub (pinned to 71377f2769)

Solutions

  1. Set request.Actor to the acting user or agent identity (e.g. the 'bd' configured user or requesting principal) before invoking the remove-dependency operation.
  2. If the caller genuinely has no identity, use the deployment's default actor (e.g. the value bd uses for local unattended changes) rather than an empty string.
  3. Check upstream translation code (CLI flags, HTTP handlers) to ensure the actor is propagated into the request struct instead of being dropped.

Example fix

// before
req := publicops.RemoveDependencyRequest{IssueID: "bd-42", DependsOnID: "bd-7"}
err := editor.ExecuteRemoveDependency(ctx, req)

// after
req := publicops.RemoveDependencyRequest{IssueID: "bd-42", DependsOnID: "bd-7", Actor: "alice"}
err := editor.ExecuteRemoveDependency(ctx, req)
Defensive patterns

Strategy: validation

Validate before calling

if req.Actor == "" {
    return fmt.Errorf("remove dependency: actor is required (set the acting user/agent)")
}
// proceed with req

Prevention

When it happens

Trigger: Calling any DependencyEditor implementation's remove-dependency path (which runs ValidateRemoveDependencyRequest) with a publicops.RemoveDependencyRequest where request.Actor == "" — e.g. a struct literal that only sets IssueID and DependsOnID, or a caller that drops the actor value when translating from a CLI/API layer.

Common situations: Hand-constructing RemoveDependencyRequest in tests or scripts and forgetting the Actor field; a CLI command that has no --actor flag configured so the value defaults to empty; refactors that renamed or removed an actor parameter upstream leaving the zero value.

Understand the failure class

Background: "Missing required field" and "field is required" errors: why libraries reject payloads that omit mandatory fields — this error's family across 20 libraries.

Related errors


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