anomalyco/sst · error
ErrStateNotFound
ErrStateNotFound
Error message
state not found
What it means
ErrStateNotFound is a sentinel error returned by provider.PullState when the backend has no state data for the requested app/stage, and surfaced through Project.Run when the initial workdir state pull finds nothing. Callers (Run in pkg/project/run.go:101) use errors.Is against it to distinguish a brand-new stage from a real backend failure.
Source
Thrown at pkg/project/provider/provider.go:252
}
return backend.putData("app", app, stage, bytes.NewReader(data))
}
func PushSnapshot(backend Home, updateID, app, stage string, data []byte) error {
slog.Info("pushing snapshot", "updateID", updateID)
err := json.Unmarshal(data, &map[string]interface{}{})
if err != nil {
return fmt.Errorf("something has corrupted the state file - refusing to upload: %w", err)
}
return backend.putData("snapshot", app, stage+"/"+updateID, bytes.NewReader(data))
}
func PushEventLog(backend Home, updateID, app, stage string, reader io.Reader) error {
slog.Info("pushing eventlog", "updateID", updateID)
return backend.putData("eventlog", app, stage+"/"+updateID, reader)
}
var ErrStateNotFound = fmt.Errorf("state not found")
func PullState(backend Home, app, stage string, out string) error {
slog.Info("pulling state", "app", app, "stage", stage, "out", out)
reader, err := backend.getData("app", app, stage)
if err != nil {
return err
}
if reader == nil {
return ErrStateNotFound
}
file, err := os.Create(out)
if err != nil {
return err
}
defer file.Close()
_, err = io.Copy(file, reader)
if err != nil {
return errView on GitHub (pinned to a0bd20f762)
Solutions
- Verify the app and stage names are correct — a typo yields this error because no state exists under that key.
- If this is genuinely a new stage, run `deploy` (or `diff`): Run auto-initializes the Pulumi stack in that case (pkg/project/run.go:105).
- Confirm you are pointed at the intended backend/home; switching backend locations makes existing state appear missing.
- Check the backend storage (app/stage key) actually contains state; if a previous deploy failed mid-push, redeploy to upload state.
Example fix
// before
err := project.Run(ctx, input) // input.Command == "refresh", stage never deployed
// after
err := project.Run(ctx, input)
if errors.Is(err, provider.ErrStateNotFound) {
input.Command = "deploy" // deploy initializes the stack for a new stage
err = project.Run(ctx, input)
} Defensive patterns
Strategy: try-catch
Validate before calling
// No pre-call validation available; optionally probe the backend first:
reader, err := backend.getData("app", app, stage)
hasState := err == nil && reader != nil Try / catch
err := provider.PullState(backend, app, stage, out)
if errors.Is(err, provider.ErrStateNotFound) {
log.Printf("no existing state for %s/%s; treating as new stage", app, stage)
return nil
}
if err != nil {
return err
} Prevention
- Pin app/stage naming in one config source to avoid typo-driven lookups.
- Confirm SST_STAGE and backend/home env vars in CI before running commands.
- Always deploy a stage at least once before running refresh/destroy/dev against it.
- Use errors.Is (not ==) to match this sentinel, since it may pass through wrapping.
When it happens
Trigger: Calling provider.PullState(backend, app, stage, out) for a stage that has never been deployed (getData returns nil reader), or running `sst Run` with a command other than deploy/diff against a stage with no stored state.
Common situations: Typo in the stage or app name when pulling state; running `sst dev`/non-deploy commands against a stage that was never deployed; pointing at the wrong backend (wrong HOME/home directory or missing SST_STAGE); state was deleted or never uploaded after a first deploy.
Related errors
- ErrStageNotFound
- ErrLockExists
- ErrLockNotFound
- something has corrupted the state file - refusing to upload:
- ErrStackRunFailed
AI-assisted analysis of anomalyco/sst@a0bd20f762 (2026-08-30).
Data as JSON: /api/errors/208668eb37a17b77.
Report an issue: GitHub.