pulumi/pulumi · error · ErrSaveStackConfig

saving stack config

Error message

saving stack config

What it means

ErrSaveStackConfig is a sentinel wrapping errors from SaveProjectStack that occur inside CreateStack after the backend stack has already been created successfully. Callers detect it with errors.Is(err, ErrSaveStackConfig) to know the backend stack exists despite the error, so it can be cleaned up or retried safely.

Source

Thrown at pkg/cmd/pulumi/stack/io.go:372

}

// InitStack creates the stack.
func InitStack(
	ctx context.Context, sink diag.Sink, ws pkgWorkspace.Context, b backend.Backend, stackName string,
	root string, opts CreateStackOptions,
) (backend.Stack, error) {
	stackRef, err := b.ParseStackReference(stackName)
	if err != nil {
		return nil, err
	}
	return CreateStack(ctx, sink, ws, b, stackRef, root, opts)
}

// ErrSaveStackConfig wraps `SaveProjectStack` errors that occur in `CreateStack` after the
// backend stack has already been successfully created. Callers can detect this case via
// `errors.Is(err, ErrSaveStackConfig)` to know that the backend stack exists despite the error
// (e.g. so they can clean it up).
var ErrSaveStackConfig = errors.New("saving stack config")

// CreateStack creates a stack with the given name, and optionally selects it as the current.
func CreateStack(ctx context.Context, sink diag.Sink, ws pkgWorkspace.Context,
	b backend.Backend, stackRef backend.StackReference, root string, opts CreateStackOptions,
) (backend.Stack, error) {
	ps, needsSave, sm, err := createSecretsManagerForNewStack(
		ctx, sink, ws, b, stackRef, opts.SecretsProvider, opts.ConfigFile)
	if err != nil {
		return nil, fmt.Errorf("could not create secrets manager for new stack: %w", err)
	}

	// If we have a non-empty secrets manager, we'll send it off to the backend as part of the initial state to be stored
	// for the stack.
	var initialState *apitype.UntypedDeployment
	if sm != nil {
		m := deploy.Manifest{
			Time:    time.Now(),
			Version: version.Version,

View on GitHub (pinned to 793f7b2e16)

Solutions

  1. Note the backend stack WAS created; delete or reuse it before retrying (errors.Is(err, ErrSaveStackConfig))
  2. Check write permissions on the project directory and the target config file
  3. Validate Pulumi.yaml (or the --config-file target) is well-formed YAML and writable
  4. Free disk space / close programs locking the file, then retry

Example fix

if err := pulumiCreateStack(...); err != nil {
    if errors.Is(err, iostack.ErrSaveStackConfig) {
        // backend stack exists despite save failure — clean up or proceed
        log.Println("stack exists on backend; fixing local config only")
    }
}
Defensive patterns

Strategy: type-guard

Validate before calling

// ensure the project config file is writable before creating
info, err := os.Stat(filepath.Join(root, "Pulumi.yaml"))
if err == nil && info.Mode().Perm()&0200 == 0 {
    return errors.New("Pulumi.yaml is not writable")
}

Type guard

func isSaveStackConfigErr(err error) bool {
    return errors.Is(err, iostack.ErrSaveStackConfig)
}

Try / catch

if err != nil {
    if errors.Is(err, iostack.ErrSaveStackConfig) {
        // backend stack exists despite save failure: cleanup or adopt
        b.DeleteStack(ctx, ref)
    }
    return err
}

Prevention

When it happens

Trigger: CreateStack succeeds on the backend, needsSave is true, and SaveProjectStack then fails — e.g. the project stack config file (Pulumi.yaml) is unwritable, malformed, or the write path is invalid.

Common situations: Read-only working directory or repo checkout, Pulumi.yaml corrupted/locked by another process, wrong --config-file path pointing outside the project, or disk-full conditions.

Related errors


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