{"record":{"id":"c9b46ab96450fabf","repo":"hashicorp/nomad","slug":"task-bucket-doesn-t-exist-and-transaction-is-not-w","errorCode":null,"errorMessage":"Task bucket doesn't exist and transaction is not writable","messagePattern":"Task bucket doesn't exist and transaction is not writable","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"client/state/db_bolt.go","lineNumber":827,"sourceCode":"}\n\n// getTaskBucket returns the bucket used to persist state about a\n// particular task. If the root allocation bucket, the specific\n// allocation or task bucket doesn't exist, they will be created as long as the\n// transaction is writable.\nfunc getTaskBucket(tx *boltdd.Tx, allocID, taskName string) (*boltdd.Bucket, error) {\n\talloc, err := getAllocationBucket(tx, allocID)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// Retrieve the specific task bucket\n\tw := tx.Writable()\n\tkey := taskBucketName(taskName)\n\ttask := alloc.Bucket(key)\n\tif task == nil {\n\t\tif !w {\n\t\t\treturn nil, fmt.Errorf(\"Task bucket doesn't exist and transaction is not writable\")\n\t\t}\n\n\t\ttask, err = alloc.CreateBucket(key)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\treturn task, nil\n}\n\n// PutDevicePluginState stores the device manager's plugin state or returns an\n// error.\nfunc (s *BoltStateDB) PutDevicePluginState(ps *dmstate.PluginState) error {\n\treturn s.db.Update(func(tx *boltdd.Tx) error {\n\t\t// Retrieve the root device manager bucket\n\t\tdevBkt, err := tx.CreateBucketIfNotExists(devManagerBucket)\n\t\tif err != nil {","sourceCodeStart":809,"sourceCodeEnd":845,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/client/state/db_bolt.go#L809-L845","documentation":"Thrown by getTaskBucket when the task-level bucket (taskBucketName(taskName)) is missing under the allocation bucket and the bolt transaction is not writable. Writable transactions auto-create the task bucket; read-only ones cannot, so the error is returned. It is the deepest of the three bucket-resolution errors in the allocations -> allocID -> taskName hierarchy.","triggerScenarios":"Reading task state/local state via a View() transaction for a task that never persisted state (bucket never created), or whose task bucket was deleted; also reached from putTaskRunnerLocalStateImpl/putTaskStateImpl when their callers run in read-only txs.","commonSituations":"Querying task state for a task name with a typo or one that was restarted before first persist; reading state right after alloc bucket creation but before any task write; migrating old alloc layouts where task buckets are absent.","solutions":["Ensure reads for a task happen only after at least one successful Update that creates the task bucket","Verify taskName spelling/casing matches what the runner persisted","Use a writable Update transaction if bucket creation is expected","Treat the error as 'no persisted state for this task' in read paths"],"exampleFix":"// before\nvar ts *structs.TaskState\ntx.Bucket(allocationsBucketName).Bucket([]byte(allocID)).Bucket(taskBucketName(taskName)).Get(taskStateKey)\n// after: use getTaskBucket-aware API in a writable tx\nts, err := GetTaskState(db, allocID, taskName)\nif err != nil {\n    if strings.Contains(err.Error(), \"Task bucket doesn't exist\") {\n        ts = nil // no state persisted yet\n    } else {\n        return err\n    }\n}","handlingStrategy":"type-guard","validationCode":"if taskName == \"\" {\n    return errors.New(\"taskName must be non-empty before reading task state\")\n}\n// ensure at least one prior Update created the task bucket\npersisted, err := taskBucketExists(db, allocID, taskName)\nif err != nil {\n    return err\n}\nif !persisted {\n    return nil\n}","typeGuard":"func isMissingTaskBucketErr(err error) bool {\n    return err != nil && strings.Contains(err.Error(), \"Task bucket doesn't exist\")\n}","tryCatchPattern":"state, err := db.GetTaskState(tx, allocID, taskName)\nif isMissingTaskBucketErr(err) {\n    state = nil // no state persisted for this task yet\n    err = nil\n} else if err != nil {\n    return err\n}","preventionTips":["Create the task bucket in a writable tx before first state read","Use exact task names from the allocation, not caller-supplied strings","Handle 'no state yet' as a normal case for freshly started tasks","Include alloc bucket existence checks before task-level reads"],"tags":["database","bolt","read-only-transaction","bucket-missing"],"backgroundTag":"bolt-transaction-not-writable","analyzedSha":"482b49bf1aec006f089bcfc7e632d8f6ac303e5e","analyzedAt":"2026-09-04T07:54:14.808Z","contentChangedAt":"2026-09-04T07:54:14.808Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}