pulumi/pulumi · error

no plan for resource %v

Error message

no plan for resource %v

What it means

While computing an update's goal plan for a resource that is being recreated (replaced) or imported, the engine expects a pre-created entry in newPlans (created during the delete/recreate or import step). If none exists, the resource's output plan cannot be filled in (Seed and Goal) and the deployment fails. This is an internal invariant: recreation and import must have registered the plan earlier in the same deployment.

Source

Thrown at pkg/resource/deploy/step_generator.go:1389

		new.Inputs = inputs
	}

	if isTargeted {
		sg.queueUntargetedDependencySames(new)
	}

	// If the resource is valid and we're generating plans then generate a plan
	if !invalid && sg.deployment.opts.GeneratePlan {
		if recreating || wasExternal || sg.isTargetedReplace(urn, old) || old == nil {
			oldInputs = nil
		}
		inputDiff := oldInputs.Diff(inputs)

		// Generate the output goal plan, if we're recreating or imported this it should already exist
		if recreating || imported {
			plan, ok := sg.deployment.newPlans.get(urn)
			if !ok {
				return nil, false, fmt.Errorf("no plan for resource %v", urn)
			}
			// The plan will have had it's Ops already partially filled in for the delete operation, but we
			// now have the information needed to fill in Seed and Goal.
			plan.Seed = randomSeed
			plan.Goal = NewGoalPlan(inputDiff, goal)
		} else {
			newResourcePlan := &ResourcePlan{
				Seed: randomSeed,
				Goal: NewGoalPlan(inputDiff, goal),
			}
			sg.deployment.newPlans.set(urn, newResourcePlan)
		}
	}

	// If there is a plan for this resource, validate that the program goal conforms to the plan.
	// If theres no plan for this resource check that nothing has been changed.
	// We don't check plans if the resource is invalid, it's going to fail anyway.
	if !invalid && sg.deployment.plan != nil {

View on GitHub (pinned to 793f7b2e16)

Solutions

  1. Upgrade the Pulumi CLI — plan generation edge cases (import/recreate) are commonly fixed in newer releases.
  2. Avoid combining --save-plan with the triggering operation (e.g. do the import or targeted replace in a normal up, then generate a plan afterwards).
  3. Check that aliases/URNs are unchanged so the recreate path finds the plan entry under the same URN.
  4. File a reproducible issue with pulumi/pulumi if a simple replace triggers it on the latest CLI.

Example fix

// before: importing while generating a plan
pulumi import aws.s3.Bucket b bucket-id --save-plan plan.json  # fails

// after: separate the import from plan generation
pulumi import aws.s3.Bucket b bucket-id
pulumi preview --save-plan plan.json
Defensive patterns

Strategy: try-catch

Try / catch

// Automation API: fall back when plan generation hits recreate/import edge cases
try {
    await stack.preview({ savePlan: "plan.json" });
} catch (err) {
    if (String(err).includes("no plan for resource")) {
        console.warn("Plan generation unsupported for this change; running normal preview.");
        await stack.preview();
    } else { throw err; }
}

Prevention

When it happens

Trigger: During `pulumi preview --save-plan` (GeneratePlan), a resource marked as recreating or imported reaches the goal-plan stage but sg.deployment.newPlans has no entry for its URN — e.g. the delete side of a replacement didn't create the plan, or the import path skipped plan registration.

Common situations: Replacing resources with aliases where the recreate URN lookup misses; `pulumi import` combined with --save-plan; engine bugs in plan generation for edge cases (targeted replace, provider replacement).

Related errors


AI-assisted analysis of pulumi/pulumi@793f7b2e16 (2026-08-31). Data as JSON: /api/errors/ba3a7272df5308f5. Report an issue: GitHub.