TheAlgorithms/Java · error · IllegalArgumentException
successors and predecessors must not be null
Error message
successors and predecessors must not be null
What it means
PredecessorConstrainedDfs.dfsRecursiveOrder(successors, predecessors, start) (the two-map overload) throws this IllegalArgumentException when either the successors or predecessors map is null. This overload requires both maps to be pre-built and consistent.
Source
Thrown at src/main/java/com/thealgorithms/graph/PredecessorConstrainedDfs.java:95
* @return immutable list of traversal events (VISITs with monotonically increasing order and SKIPs with messages)
* @throws IllegalArgumentException if {@code successors} is null
*/
public static <T> List<TraversalEvent<T>> dfsRecursiveOrder(Map<T, List<T>> successors, T start) {
if (successors == null) {
throw new IllegalArgumentException("successors must not be null");
}
// derive predecessors once
Map<T, List<T>> predecessors = derivePredecessors(successors);
return dfsRecursiveOrder(successors, predecessors, start);
}
/**
* Same as {@link #dfsRecursiveOrder(Map, Object)} but with an explicit predecessors map.
*/
public static <T> List<TraversalEvent<T>> dfsRecursiveOrder(Map<T, List<T>> successors, Map<T, List<T>> predecessors, T start) {
if (successors == null || predecessors == null) {
throw new IllegalArgumentException("successors and predecessors must not be null");
}
if (start == null) {
return List.of();
}
if (!successors.containsKey(start) && !appearsAnywhere(successors, start)) {
return List.of(); // start not present in graph
}
List<TraversalEvent<T>> events = new ArrayList<>();
Set<T> visited = new HashSet<>();
int[] order = {0};
dfs(start, successors, predecessors, visited, order, events);
return Collections.unmodifiableList(events);
}
private static <T> void dfs(T currentNode, Map<T, List<T>> successors, Map<T, List<T>> predecessors, Set<T> visited, int[] order, List<TraversalEvent<T>> result) {
if (!visited.add(currentNode)) {View on GitHub (pinned to fdfb9a395b)
Solutions
- Use the single-argument overload if you only have successors; it derives predecessors for you.
- If calling the two-argument overload, build predecessors first via the same derivePredecessors logic.
- Guard: if either map is null, fall back to the single-arg overload.
Example fix
// before List<TraversalEvent<T>> e = PredecessorConstrainedDfs.dfsRecursiveOrder(successors, null, start); // after List<TraversalEvent<T>> e = PredecessorConstrainedDfs.dfsRecursiveOrder(successors, start); // single-arg derives predecessors
Defensive patterns
Strategy: validation
Validate before calling
if (successors == null || predecessors == null) {
// fall back to single-arg overload which derives predecessors
return PredecessorConstrainedDfs.dfsRecursiveOrder(successors, start);
} Prevention
- Prefer the single-argument overload when you only have successors.
- Derive predecessors with the same logic the library uses.
- Guard both maps against null before calling the two-arg overload.
When it happens
Trigger: Calling the three-argument overload with successors null, predecessors null, or both null.
Common situations: Passing a derived predecessors map that was never computed. Mismatch between the single-arg and two-arg overloads where callers forget to supply predecessors. Field injection leaving one map null.
Related errors
- successors must not be null
- Capacity matrix must not be null or empty
- Capacity matrix must not be null or empty
- Cost matrix must not be null or empty
- Capacity matrix must not be null or empty
AI-assisted analysis of TheAlgorithms/Java@fdfb9a395b (2026-08-13).
Data as JSON: /api/errors/cca0c78274a4a38e.
Report an issue: GitHub.