dgraph-io/badger · error

ErrGCInReadOnlyMode

ErrGCInReadOnlyMode

Error message

Cannot run value log GC when DB is opened in ReadOnly mode

What it means

ErrGCInReadOnlyMode is a sentinel error returned by DB.RunValueLogGC when the badger DB was opened with the ReadOnly option set to true. Garbage collection rewrites and truncates value log files, a write operation that a read-only DB cannot perform, so the call is rejected immediately after the InMemory check in RunValueLogGC (db.go:1309).

Source

Thrown at errors.go:113

	// ErrNilCallback is returned when subscriber's callback is nil.
	ErrNilCallback = stderrors.New("Callback cannot be nil")

	// ErrEncryptionKeyMismatch is returned when the storage key is not
	// matched with the key previously given.
	ErrEncryptionKeyMismatch = stderrors.New("Encryption key mismatch")

	// ErrInvalidDataKeyID is returned if the datakey id is invalid.
	ErrInvalidDataKeyID = stderrors.New("Invalid datakey id")

	// ErrInvalidEncryptionKey is returned if length of encryption keys is invalid.
	ErrInvalidEncryptionKey = stderrors.New("Encryption key's length should be" +
		"either 16, 24, or 32 bytes")
	// ErrGCInMemoryMode is returned when db.RunValueLogGC is called in in-memory mode.
	ErrGCInMemoryMode = stderrors.New("Cannot run value log GC when DB is opened in InMemory mode")

	// ErrGCInReadOnlyMode is returned when db.RunValueLogGC is called in read-only mode.
	ErrGCInReadOnlyMode = stderrors.New("Cannot run value log GC when DB is opened in ReadOnly mode")

	// ErrDBClosed is returned when a get operation is performed after closing the DB.
	ErrDBClosed = stderrors.New("DB Closed")
)

View on GitHub (pinned to 2a001d466f)

Solutions

  1. Skip RunValueLogGC entirely for DBs opened in ReadOnly mode.
  2. Run value log GC on the writable primary instance instead.
  3. If the directory must be writable again, reopen the DB without WithReadOnly(true).
  4. Treat the error as a no-op: if errors.Is(err, badger.ErrGCInReadOnlyMode), log and continue.

Example fix

// before
err := db.RunValueLogGC(0.5)
// after
if !opts.ReadOnly {
    if err := db.RunValueLogGC(0.5); err != nil && !errors.Is(err, badger.ErrGCInReadOnlyMode) {
        return err
    }
}
Defensive patterns

Strategy: validation

Validate before calling

func shouldRunGC(db *badger.DB, readOnly bool) bool {
    return !readOnly // GC needs write access to value log files
}
// call site:
if !readOnly {
    if err := db.RunValueLogGC(0.5); err != nil { ... }
}

Type guard

func canRunValueLogGC(opt badger.Options) bool {
    return !opt.ReadOnly && !opt.InMemory
}

Try / catch

if err := db.RunValueLogGC(0.5); err != nil {
    if errors.Is(err, badger.ErrGCInReadOnlyMode) {
        return nil // expected on read-only DBs, skip GC
    }
    return err
}

Prevention

When it happens

Trigger: Calling db.RunValueLogGC(discardRatio) on a DB opened with badger.Open(opts.WithReadOnly(true)) — e.g. a replica or a database opened for inspection on read-only storage.

Common situations: Opening a badger directory on a read-only filesystem or a secondary/read-only replica for analytics, then reusing maintenance code that runs GC; test code like db_test.go:1794 that explicitly exercises this path.

Related errors


AI-assisted analysis of dgraph-io/badger@2a001d466f (2026-09-05). Data as JSON: /api/errors/0eb7db1df206b40d. Report an issue: GitHub.