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

  1. Use the single-argument overload if you only have successors; it derives predecessors for you.
  2. If calling the two-argument overload, build predecessors first via the same derivePredecessors logic.
  3. 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

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


AI-assisted analysis of TheAlgorithms/Java@fdfb9a395b (2026-08-13). Data as JSON: /api/errors/cca0c78274a4a38e. Report an issue: GitHub.