{"record":{"id":"769468265c9a7742","repo":"dgraph-io/badger","slug":"errreadonlytxn","errorCode":"ErrReadOnlyTxn","errorMessage":"No sets or deletes are allowed in a read-only transaction","messagePattern":"No sets or deletes are allowed in a read-only transaction","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"errors.go","lineNumber":34,"sourceCode":")\n\nvar (\n\t// ErrValueLogSize is returned when opt.ValueLogFileSize option is not within the valid\n\t// range.\n\tErrValueLogSize = stderrors.New(\"Invalid ValueLogFileSize, must be in range [1MB, 2GB)\")\n\n\t// ErrKeyNotFound is returned when key isn't found on a txn.Get.\n\tErrKeyNotFound = stderrors.New(\"Key not found\")\n\n\t// ErrTxnTooBig is returned if too many writes are fit into a single transaction.\n\tErrTxnTooBig = stderrors.New(\"Txn is too big to fit into one request\")\n\n\t// ErrConflict is returned when a transaction conflicts with another transaction. This can\n\t// happen if the read rows had been updated concurrently by another transaction.\n\tErrConflict = stderrors.New(\"Transaction Conflict. Please retry\")\n\n\t// ErrReadOnlyTxn is returned if an update function is called on a read-only transaction.\n\tErrReadOnlyTxn = stderrors.New(\"No sets or deletes are allowed in a read-only transaction\")\n\n\t// ErrDiscardedTxn is returned if a previously discarded transaction is reused.\n\tErrDiscardedTxn = stderrors.New(\"This transaction has been discarded. Create a new one\")\n\n\t// ErrEmptyKey is returned if an empty key is passed on an update function.\n\tErrEmptyKey = stderrors.New(\"Key cannot be empty\")\n\n\t// ErrInvalidKey is returned if the key has a special !badger! prefix,\n\t// reserved for internal usage.\n\tErrInvalidKey = stderrors.New(\"Key is using a reserved !badger! prefix\")\n\n\t// ErrBannedKey is returned if the read/write key belongs to any banned namespace.\n\tErrBannedKey = stderrors.New(\"Key is using the banned prefix\")\n\n\t// ErrThresholdZero is returned if threshold is set to zero, and value log GC is called.\n\t// In such a case, GC can't be run.\n\tErrThresholdZero = stderrors.New(\n\t\t\"Value log GC can't run because threshold is set to zero\")","sourceCodeStart":16,"sourceCodeEnd":52,"githubUrl":"https://github.com/dgraph-io/badger/blob/2a001d466f6b71a917319a1db41f99860e16e269/errors.go#L16-L52","documentation":"ErrReadOnlyTxn is returned when a mutation (Set/SetEntry/Delete/modify) is attempted on a read-only transaction (txn.go:356). Read-only transactions come from db.View() or db.NewTransactionAt(ts, false) and cannot write.","triggerScenarios":"Calling txn.Set/SetEntry/Delete inside db.View(); passing a read-only txn into a mutating helper; creating a txn with NewTransactionAt(ts, false) then writing.","commonSituations":"Refactoring Update() to View() for read paths while leaving a Set inside; shared helpers that both read and write receiving a read-only txn.","solutions":["Use db.Update (or NewTransactionAt(ts, true)) when the code writes","Split read-only and mutating logic into separate View/Update blocks","Check txn.update before mutating in generic helpers"],"exampleFix":"// before\nerr := db.View(func(txn *Txn) error {\n    return txn.Set([]byte(\"k\"), []byte(\"v\")) // ErrReadOnlyTxn\n})\n// after\nerr := db.Update(func(txn *Txn) error {\n    return txn.Set([]byte(\"k\"), []byte(\"v\"))\n})","handlingStrategy":"validation","validationCode":"func mustBeWritable(txn *badger.Txn) error {\n    if !txn.update { // unexported; instead track writability in your own flag\n        return errors.New(\"read-only transaction\")\n    }\n    return nil\n}\n// practical caller-side check: only pass txns from db.Update/NewTransaction(true) to mutators","typeGuard":"func isWritableTxn(txn *badger.Txn, writable bool) bool { return writable }","tryCatchPattern":"if err := txn.Set(k, v); err != nil {\n    if errors.Is(err, badger.ErrReadOnlyTxn) {\n        return fmt.Errorf(\"mutation attempted in View: %w\", err)\n    }\n    return err\n}","preventionTips":["Do all mutations in db.Update, all pure reads in db.View","Never pass read-only txns into mutating helper functions","Create txns with update=true where writes are possible"],"tags":["badger","transaction","read-only","api-misuse"],"backgroundTag":"read-only-violation","analyzedSha":"2a001d466f6b71a917319a1db41f99860e16e269","analyzedAt":"2026-09-05T13:00:02.264Z","contentChangedAt":"2026-09-05T13:00:02.264Z","schemaVersion":2},"datasetVersion":"2026-09-12T17:17:11.597Z"}