{"record":{"id":"4416d6a984dc53d1","repo":"hashicorp/terraform","slug":"can-t-delete-default-state-4416d6","errorCode":null,"errorMessage":"can't delete default state","messagePattern":"can't delete default state","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/backend/remote-state/s3/backend_state.go","lineNumber":142,"sourceCode":"\t// not our key, so don't include it in our listing\n\tif parts[1] != b.keyName {\n\t\treturn \"\"\n\t}\n\n\treturn parts[0]\n}\n\nfunc (b *Backend) DeleteWorkspace(name string, _ bool) tfdiags.Diagnostics {\n\tvar diags tfdiags.Diagnostics\n\n\tlog := logger()\n\tlog = logWithOperation(log, operationBackendDeleteWorkspace)\n\tlog = log.With(\n\t\tlogKeyBackendWorkspace, name,\n\t)\n\n\tif name == backend.DefaultStateName || name == \"\" {\n\t\treturn diags.Append(fmt.Errorf(\"can't delete default state\"))\n\t}\n\n\tlog.Info(\"Deleting workspace\")\n\n\tclient, err := b.remoteClient(name)\n\tif err != nil {\n\t\treturn diags.Append(err)\n\t}\n\n\treturn diags.Append(client.Delete())\n}\n\n// get a remote client configured for this state\nfunc (b *Backend) remoteClient(name string) (*RemoteClient, error) {\n\tif name == \"\" {\n\t\treturn nil, errors.New(\"missing state name\")\n\t}\n","sourceCodeStart":124,"sourceCodeEnd":160,"githubUrl":"https://github.com/hashicorp/terraform/blob/d32a084675427f5ac3f7d2868578ef8b2c1dc525/internal/backend/remote-state/s3/backend_state.go#L124-L160","documentation":"Thrown by Backend.DeleteWorkspace in the S3 state backend when name equals backend.DefaultStateName (\"default\") or \"\". Same guard as the pg backend: the default workspace is the canonical state and cannot be deleted through this API. The check runs before the remote client Delete() so no S3 object is touched.","triggerScenarios":"DeleteWorkspace(name, _) called with name == \"default\" or \"\". Triggered by `tofu workspace delete default` or any loop that tries to delete every workspace including default.","commonSituations":"Teardown script enumerating `tofu workspace list` and deleting each line; CI that auto-creates and deletes ephemeral workspaces but fails to skip default; misunderstanding default-state immutability.","solutions":["Filter out 'default' and empty lines in any workspace-deletion loop.","Use `tofu destroy` to clear default state instead of deleting the workspace.","Validate workspace names from upstream config before calling delete."],"exampleFix":"# before\nfor ws in $(tofu workspace list | tr -d '*'); do tofu workspace delete \"$ws\"; done\n# after\nfor ws in $(tofu workspace list | tr -d '*' | grep -v '^default$'); do tofu workspace delete \"$ws\"; done","handlingStrategy":"validation","validationCode":"func deleteWorkspace(name string) error {\n    if name == backend.DefaultStateName || name == \"\" {\n        return fmt.Errorf(\"protected workspace %q; use `tofu destroy` instead\", name)\n    }\n    // ... proceed\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Filter 'default' out of workspace-deletion loops.","Validate upstream workspace-name inputs before delete.","Use `tofu destroy` to clear default state."],"tags":["s3","aws","workspace","default-state","guard"],"backgroundTag":null,"analyzedSha":"d32a084675427f5ac3f7d2868578ef8b2c1dc525","analyzedAt":"2026-08-11T18:43:52.779Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}