pulumi/pulumi · error

update timeout changed (expected %v)

Error message

update timeout changed (expected %v)

What it means

checkGoal compares CustomTimeouts between plan and program; this branch fires when the update timeout recorded in the plan differs from the program's current value.

Source

Thrown at pkg/resource/deploy/plan.go:625

	default:
		expected := "no value"
		if rp.Goal.DeleteBeforeReplace != nil {
			expected = strconv.FormatBool(*rp.Goal.DeleteBeforeReplace)
		}
		return fmt.Errorf("deleteBeforeReplace changed (expected %v)", expected)
	}

	// Check that the import ID is identical.
	if rp.Goal.ID != programGoal.ID {
		return fmt.Errorf("importID changed (expected %v)", rp.Goal.ID)
	}

	// Check that the timeouts are identical.
	switch {
	case rp.Goal.CustomTimeouts.Create != programGoal.CustomTimeouts.Create:
		return fmt.Errorf("create timeout changed (expected %v)", rp.Goal.CustomTimeouts.Create)
	case rp.Goal.CustomTimeouts.Update != programGoal.CustomTimeouts.Update:
		return fmt.Errorf("update timeout changed (expected %v)", rp.Goal.CustomTimeouts.Update)
	case rp.Goal.CustomTimeouts.Delete != programGoal.CustomTimeouts.Delete:
		return fmt.Errorf("delete timeout changed (expected %v)", rp.Goal.CustomTimeouts.Delete)
	case rp.Goal.CustomTimeouts.Read != programGoal.CustomTimeouts.Read:
		return fmt.Errorf("read timeout changed (expected %v)", rp.Goal.CustomTimeouts.Read)
	}

	// Check that the ignoreChanges sets are identical.
	if message, changed := rp.diffStringSets(rp.Goal.IgnoreChanges, programGoal.IgnoreChanges); changed {
		return fmt.Errorf("ignoreChanges changed: %v", message)
	}

	// Check that the additionalSecretOutputs sets are identical.
	if message, changed := rp.diffPropertyKeys(
		rp.Goal.AdditionalSecretOutputs, programGoal.AdditionalSecretOutputs); changed {
		return fmt.Errorf("additionalSecretOutputs changed: %v", message)
	}

	// Check that the dependencies match.

View on GitHub (pinned to 793f7b2e16)

Solutions

  1. Restore the update timeout to the planned value, or regenerate the plan
  2. Re-save the plan if the timeout change is intentional
  3. Discard the saved plan and apply without a plan
  4. Keep timeout config synchronized with any pending plan files in CI

Example fix

// before: update timeout changed after plan saved
{ customTimeouts: { update: "10m" } }
// after: match planned goal
{ customTimeouts: { update: "20m" } }
Defensive patterns

Strategy: validation

Validate before calling

if curTimeouts.Update != planTimeouts.Update {
	return errors.New("update timeout drifted from saved plan")
}

Try / catch

if err := up(plan); err != nil && strings.Contains(err.Error(), "update timeout changed") {
	return regeneratePlan()
}

Prevention

When it happens

Trigger: Replaying a saved plan after changing `customTimeouts: { update: "20m" }` on the resource, or adding/removing the update timeout after the plan was saved.

Common situations: Extending update timeouts for long-running in-place updates (e.g. cluster upgrades) while a plan is pending; inconsistent timeout edits across environments sharing a plan.

Understand the failure class

Related errors


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