nektos/act · error

unable to build dependency graph for %s (%s)

Error message

unable to build dependency graph for %s (%s)

What it means

PlanJobs builds stages by repeatedly moving jobs whose dependencies are all satisfied into the next stage. If a pass adds zero runs but jobs remain, some job's `needs:` references either do not exist or form a cycle, and planning aborts. The message names the workflow (name and file) where the graph is unresolvable.

Source

Thrown at pkg/model/planner.go:375

		jobIDs = newJobIDs
	}

	// next, build an execution graph
	stages := make([]*Stage, 0)
	for len(jobDependencies) > 0 {
		stage := new(Stage)
		for jID, jDeps := range jobDependencies {
			// make sure all deps are in the graph already
			if listInStages(jDeps, stages...) {
				stage.Runs = append(stage.Runs, &Run{
					Workflow: w,
					JobID:    jID,
				})
				delete(jobDependencies, jID)
			}
		}
		if len(stage.Runs) == 0 {
			return nil, fmt.Errorf("unable to build dependency graph for %s (%s)", w.Name, w.File)
		}
		stages = append(stages, stage)
	}

	return stages, nil
}

// return true iff all strings in srcList exist in at least one of the stages
func listInStages(srcList []string, stages ...*Stage) bool {
	for _, src := range srcList {
		found := false
		for _, stage := range stages {
			for _, search := range stage.GetJobIDs() {
				if src == search {
					found = true
				}
			}
		}

View on GitHub (pinned to 4f41128141)

Solutions

  1. Check the workflow file named in the message; verify every `needs:` entry matches an existing job ID exactly (case-sensitive).
  2. Break any dependency cycle by removing or reordering one needs edge.
  3. If a dependency is event-conditional, either make the dependent job conditional the same way or restructure so all scheduled jobs are plannable.

Example fix

# before
jobs:
  build:
    needs: deplooy
# after
jobs:
  build:
    needs: deploy
Defensive patterns

Strategy: validation

Validate before calling

func validateNeeds(wf *Workflow) error {
    ids := map[string]bool{}
    for id := range wf.Jobs { ids[id] = true }
    for id, j := range wf.Jobs {
        for _, dep := range j.Needs {
            if !ids[dep] { return fmt.Errorf("job %q needs unknown job %q", id, dep) }
        }
    }
    // additionally run a DFS cycle check over the needs edges
    return nil
}

Try / catch

if err != nil && strings.Contains(err.Error(), "unable to build dependency graph") {
    // the message names the workflow file; inspect its needs: edges for typos/cycles
}

Prevention

When it happens

Trigger: A job declares `needs: deplooy` (typo of deploy); a cycle like a→b→a; or a job depending on a job filtered out by the event/condition so it never enters a stage.

Common situations: Renaming a job without updating dependents' needs; copy-paste workflows introducing cyclic needs; references to jobs that only run on a different event.

Related errors


AI-assisted analysis of nektos/act@4f41128141 (2026-08-15). Data as JSON: /api/errors/9449b3af3be4a1d6. Report an issue: GitHub.