hashicorp/nomad · error

BoltDB store not found at %s: %w

Error message

BoltDB store not found at %s: %w

What it means

preflightChecks stats <raftDir>/raft.db before anything else; this error wraps the os.Stat failure when the BoltDB store file is missing or unreadable. No files are created or modified, so it is a safe, immediate abort. It also fires when raft.db exists but cannot be stat'ed due to path or permission problems on parent directories.

Source

Thrown at helper/raftutil/migrate.go:186

	if parent == nil {
		for range sub {
		}
		return
	}
	for msg := range sub {
		select {
		case parent <- msg:
		default:
			// Drop message if consumer is slow to avoid blocking migration.
		}
	}
}

func preflightChecks(boltPath, walDir, raftDir string) error {
	// Verify the BoltDB file exists.
	boltInfo, err := os.Stat(boltPath)
	if err != nil {
		return fmt.Errorf("BoltDB store not found at %s: %w", boltPath, err)
	}

	// Verify the WAL directory does not already exist.
	if _, err := os.Stat(walDir); err == nil {
		return fmt.Errorf(
			"WAL directory already exists at %s; remove it before retrying migration",
			walDir)
	}

	// Check write permissions on raft directory.
	testFile := filepath.Join(raftDir, ".permission-test")
	if err := os.WriteFile(testFile, []byte("test"), 0o600); err != nil {
		return fmt.Errorf("insufficient write permissions in %s: %w", raftDir, err)
	}
	os.Remove(testFile)

	// Check available disk space.
	usage, err := disk.Usage(raftDir)

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. Verify the correct raft data directory (the one containing raft.db) and re-run with that path.
  2. If raft.db was already renamed to raft.db.migrated.<timestamp>, migration already succeeded — check for the wal directory and start the server.
  3. Check parent-directory permissions/execute bits allowing stat traversal.
  4. If the node never initialized raft, there is nothing to migrate — skip the migration.

Example fix

// before
err := MigrateToWAL(ctx, "/var/lib/nomad/wrong-dir", progress)
// after
err := MigrateToWAL(ctx, "/var/lib/nomad/data/raft", progress) // dir containing raft.db
Defensive patterns

Strategy: validation

Validate before calling

boltPath := filepath.Join(raftDir, "raft.db")
if fi, err := os.Stat(boltPath); err != nil || fi.IsDir() {
    // check for an already-migrated backup before failing
    matches, _ := filepath.Glob(boltPath + ".migrated.*")
    if len(matches) > 0 {
        return fmt.Errorf("migration already completed: %s (wal/ should exist)", matches[0])
    }
    return fmt.Errorf("no BoltDB store at %s; verify raftDir", boltPath)
}

Try / catch

err := raftutil.MigrateToWAL(ctx, raftDir, progress)
if err != nil && strings.Contains(err.Error(), "BoltDB store not found") {
    // verify raftDir points at the directory containing raft.db before retrying
}

Prevention

When it happens

Trigger: os.Stat(raftDir/raft.db) returns an error: the file does not exist (wrong raftDir passed, fresh server that never ran, BoltDB already migrated/renamed), the path is a dangling symlink, or traversal permission denied on a parent directory.

Common situations: Operator passes the wrong -data-dir or runs migration on a non-server node; running migration twice — the second run finds raft.db renamed to raft.db.migrated.<ts>; typo in raftDir or relative path resolved from wrong working directory.

Understand the failure class

Background: "File not found" and ENOENT errors: why libraries can't find a file that should exist — this error's family across 50 libraries.

Related errors


AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04). Data as JSON: /api/errors/3c517bef53fc3ad5. Report an issue: GitHub.