dgraph-io/badger · critical
Unable to open mem dir.
Error message
Unable to open mem dir.
What it means
At DB open, badger lists the configured Options.Dir to discover memtable WAL files. This error wraps the os.ReadDir failure, so the memtable directory itself could not be read (missing, permission denied, not a directory, or I/O error). In-memory mode skips this entirely.
Source
Thrown at memtable.go:50
// both to the WAL and the skiplist. On a crash, the WAL is replayed to bring the skiplist back to
// its pre-crash form.
type memTable struct {
// TODO: Give skiplist z.Calloc'd []byte.
sl *skl.Skiplist
wal *logFile
maxVersion uint64
opt Options
buf *bytes.Buffer
}
func (db *DB) openMemTables(opt Options) error {
// We don't need to open any tables in in-memory mode.
if db.opt.InMemory {
return nil
}
files, err := os.ReadDir(db.opt.Dir)
if err != nil {
return errFile(err, db.opt.Dir, "Unable to open mem dir.")
}
var fids []int
for _, file := range files {
if !strings.HasSuffix(file.Name(), memFileExt) {
continue
}
fsz := len(file.Name())
fid, err := strconv.ParseInt(file.Name()[:fsz-len(memFileExt)], 10, 64)
if err != nil {
return errFile(err, file.Name(), "Unable to parse log id.")
}
fids = append(fids, int(fid))
}
// Sort in ascending order.
sort.Slice(fids, func(i, j int) bool {
return fids[i] < fids[j]View on GitHub (pinned to 2a001d466f)
Solutions
- Verify the directory exists and create it if not: os.MkdirAll(dir, 0700) before badger.Open
- Check process permissions: ls -ld <dir> and ensure the running user can read/execute it
- Confirm the path is a directory, not a file, and that the volume is mounted (docker/k8s volume mounts)
- If in-memory mode is intended, set Options.InMemory=true so no dir is required
Example fix
// before
badger.Open(badger.DefaultOptions("/data/badger"))
// after
if err := os.MkdirAll("/data/badger", 0o700); err != nil {
return err
}
db, err := badger.Open(badger.DefaultOptions("/data/badger")) Defensive patterns
Strategy: validation
Validate before calling
info, err := os.Stat(dir)
if err != nil {
if os.IsNotExist(err) { os.MkdirAll(dir, 0o700) }
} else if !info.IsDir() {
return fmt.Errorf("%s is not a directory", dir)
} Type guard
func dirReadable(dir string) error {
fi, err := os.Stat(dir)
if err != nil { return err }
if !fi.IsDir() { return fmt.Errorf("not a directory: %s", dir) }
f, err := os.Open(dir)
if err != nil { return err }
return f.Close()
} Try / catch
db, err := badger.Open(opt)
if err != nil && strings.Contains(err.Error(), "Unable to open mem dir") {
// surface actionable guidance for perms/mount issues
return fmt.Errorf("check that %q exists, is a directory, and is readable by uid %d: %w", opt.Dir, os.Getuid(), err)
} Prevention
- Call os.MkdirAll on Options.Dir before opening
- In containers, verify volume mounts at startup with a readiness check
- Avoid running once as root then as an unprivileged user (permission drift)
- Prefer Options.InMemory=true when no persistence is needed
When it happens
Trigger: Calling badger.Open (or OpenDB) with Options.Dir pointing to a path that does not exist, is not readable by the process, is a file instead of a directory, or lives on a failed/unmounted volume.
Common situations: Wrong path in config or env var; running in a container where the volume was not mounted; permission differences after running once as root then as a normal user; NFS/network mount outage.
Related errors
- Cannot find directory %q for read-only open
- Unable to open log dir.
- Unable to parse log id.
- File %s already exists
- ErrValueLogSize
AI-assisted analysis of dgraph-io/badger@2a001d466f (2026-09-05).
Data as JSON: /api/errors/93c5d3b64eb1a00d.
Report an issue: GitHub.