gastownhall/beads · error · storage.ErrValidation
%w: remove dependency requires both endpoints
Error message
%w: remove dependency requires both endpoints
What it means
ValidateRemoveDependencyRequest rejects a RemoveDependencyRequest missing either endpoint of the dependency edge: the IssueID whose dependency is being removed, or the DependsOnID it pointed at. An edge removal needs both ends to identify the single row to delete, so requests with either ID empty are refused with storage.ErrValidation before touching storage.
Source
Thrown at internal/storage/issueops/dependency_editor.go:57
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
// and not on which flag was used, so a one-line bulk file now names its edge
// instead of reading "add 1 edges": one edge is one edge however it was
// spelled.View on GitHub (pinned to 71377f2769)
Solutions
- Populate both request.IssueID and request.DependsOnID with the two endpoints of the edge being removed.
- If only one ID is known, look up the dependency list for that issue first (e.g. a dependency-records query) to find the missing endpoint.
- Add a pre-flight check in the calling layer that surfaces 'both issue IDs are required' to the user instead of reaching storage.
Example fix
// before
req := publicops.RemoveDependencyRequest{IssueID: "bd-42", Actor: "alice"} // DependsOnID empty
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.IssueID == "" || req.DependsOnID == "" {
return fmt.Errorf("remove dependency: both issue and depends-on IDs are required")
}
// proceed with req Prevention
- Resolve both endpoints from the dependency list of the issue before issuing a removal.
- Validate user-supplied IDs at the CLI/handler boundary before building the request struct.
- In bulk removal loops, skip or log entries with missing endpoints rather than passing them through.
When it happens
Trigger: Calling a DependencyEditor's remove-dependency path with publicops.RemoveDependencyRequest where request.IssueID == "" or request.DependsOnID == "" — typically when one side of the edge comes from optional user input or a variable that failed to resolve.
Common situations: A CLI user passing only one issue ID to a dependency-remove command; scripting that interpolates an empty variable for one endpoint; list-driven bulk removal where some entries lack a DependsOnID 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
- no store is open for this workspace
- no absolute native user directory is available
- ExternalDoltConfig: set either Socket OR (Host, Port), not b
- ExternalDoltConfig: must set Socket or (Host, Port)
- ExternalDoltConfig: Host requires Port
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/952d1170a7057d61.
Report an issue: GitHub.