{"record":{"id":"dd062ccdf7b67ac7","repo":"hashicorp/terraform","slug":"error-uploading-state-w","errorCode":null,"errorMessage":"error uploading state: %w","messagePattern":"error uploading state: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/cloud/state.go","lineNumber":234,"sourceCode":"\n\tstateFile, err := statefile.Read(bytes.NewReader(buf.Bytes()))\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to read state: %w\", err)\n\t}\n\n\tov, err := jsonstate.MarshalOutputs(stateFile.State.RootOutputValues)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to translate outputs: %w\", err)\n\t}\n\tjsonStateOutputs, err := json.Marshal(ov)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to marshal outputs to json: %w\", err)\n\t}\n\n\terr = s.uploadState(s.lineage, s.serial, s.forcePush, buf.Bytes(), jsonState, jsonStateOutputs)\n\tif err != nil {\n\t\ts.stateUploadErr = true\n\t\treturn fmt.Errorf(\"error uploading state: %w\", err)\n\t}\n\t// After we've successfully persisted, what we just wrote is our new\n\t// reference state until someone calls RefreshState again.\n\t// We've potentially overwritten (via force) the state, lineage\n\t// and / or serial (and serial was incremented) so we copy over all\n\t// three fields so everything matches the new state and a subsequent\n\t// operation would correctly detect no changes to the lineage, serial or state.\n\ts.readState = s.state.DeepCopy()\n\ts.readLineage = s.lineage\n\ts.readSerial = s.serial\n\n\treturn nil\n}\n\n// ShouldPersistIntermediateState implements statemgr.IntermediateStateConditionalPersister\nfunc (s *State) ShouldPersistIntermediateState(info *statemgr.IntermediateStatePersistInfo) bool {\n\tif info.ForcePersist {\n\t\treturn true","sourceCodeStart":216,"sourceCodeEnd":252,"githubUrl":"https://github.com/hashicorp/terraform/blob/c9def3e214014c1188faabfc4a5bde5095139765/internal/cloud/state.go#L216-L252","documentation":"Wraps any failure of StateVersions.Upload (or the compatibility StateVersions.Create fallback) at the end of PersistState when uploading a new state version to HCP Terraform/TFE. On failure it sets s.stateUploadErr=true, which makes the subsequent Unlock a no-op so the workspace stays locked and no unsafe change is applied until a good state is uploaded.","triggerScenarios":"PersistState calls uploadState and the StateVersions.Upload API returns an error: network failure, 401/403 auth, 409 lineage/serial conflict, 5xx server error, or workspace state rejecting a new version.","commonSituations":"Transient network blips, expired or revoked API token, two concurrent runs racing on the same workspace (serial/lineage mismatch), or an HCP/TFE outage/rate-limit.","solutions":["Re-run the operation; Terraform re-locks and re-uploads and transient network/5xx errors usually clear.","Verify the API token is valid: terraform logout && terraform login.","Confirm no other concurrent run is writing to the workspace.","Check the HCP Terraform / Terraform Enterprise status page and retry.","If a serial/lineage conflict persists, confirm who holds the lock and use terraform force-unlock only when safe."],"exampleFix":"# before: stale / expired token causes upload failure\nterraform apply   # -> error uploading state: ...\n\n# after: refresh credentials then retry\nterraform logout\nterraform login\nterraform apply","handlingStrategy":"retry","validationCode":"// Pre-flight: token present and API reachable before attempting a write\nif os.Getenv(\"TF_TOKEN_app_terraform_io\") == \"\" && cfg.Token == \"\" {\n    return errors.New(\"no API token configured; run terraform login\")\n}\n// Optionally ping the current-state endpoint to confirm connectivity/auth\nif _, err := client.StateVersions.ReadCurrent(ctx, workspace.ID); err != nil && !errors.Is(err, tfe.ErrResourceNotFound) {\n    return fmt.Errorf(\"pre-upload check failed: %w\", err)\n}","typeGuard":null,"tryCatchPattern":"err := state.PersistState(schemas)\nif err != nil && (isRetryable(err) || isTransientHTTP(err)) {\n    // re-lock and retry upload a bounded number of times\n}\n// NOTE: on failure the workspace is intentionally left locked; resolve the\n// root cause or force-unlock deliberately rather than silently continuing.","preventionTips":["Keep the API token fresh (terraform login)","Serialize runs per workspace to avoid serial/lineage conflicts","Treat the held lock on upload failure as intentional safety, not a bug"],"tags":["state-upload","network","auth","persist","locking"],"analyzedSha":"c9def3e214014c1188faabfc4a5bde5095139765","analyzedAt":"2026-08-07T15:39:49.278Z","schemaVersion":2},"datasetVersion":"2026-08-07T21:17:07.882Z"}