crowdsecurity/crowdsec · critical

failed to create SQLite database file

Error message

failed to create SQLite database file %q: %w

What it means

NewClient pre-creates the SQLite file when db_config.type is sqlite and the path isn't :memory:. If os.OpenFile(O_CREATE|O_RDWR, 0600) cannot create/open the file, the error is wrapped with this message and client startup aborts. This runs only on first startup (file does not exist yet).

Solutions

  1. Check that the directory containing db_path exists and is writable by the crowdsec user (mkdir -p / chown)
  2. Verify db_path in the YAML points to a file path, not a directory, and is not :memory:-typoed
  3. Check for read-only mounts or MAC-policy (SELinux/AppArmor) denials in audit logs
  4. Run crowdsec as a user with write access to the data dir

Example fix

// before (crowdsec.yaml)
db_config:
  type: sqlite
  db_path: /var/lib/crowdsec/data/crowdsec.db   # dir missing
// after
sudo mkdir -p /var/lib/crowdsec/data && sudo chown crowdsec:crowdsec /var/lib/crowdsec/data
Defensive patterns

Strategy: validation

Validate before calling

// before starting crowdsec
path := "/var/lib/crowdsec/data/crowdsec.db"
dir := filepath.Dir(path)
if info, err := os.Stat(dir); err != nil || !info.IsDir() {
	os.MkdirAll(dir, 0o750)
}
f, err := os.OpenFile(path, os.O_CREATE|os.O_RDWR, 0o600)
if err != nil { log.Fatalf("db path not writable: %v", err) }
f.Close()

Prevention

When it happens

Trigger: The parent directory does not exist or is not writable, the path points to a directory, permission is denied (wrong user, read-only filesystem, sandboxed dir), or the path is invalid for the OS.

Common situations: db_config.db_path in /etc/crowdsec/config.yaml pointing at a non-existent directory or a path the crowdsec user can't write (e.g. running under systemd with a different User=); Docker volume mounted read-only; SELinux/AppArmor denial.

Understand the failure class

Background: "open() failed", "failed to open file", "cannot create file" — what a file open error means and how to fix it — this error's family across 42 libraries.

Related errors


AI-assisted analysis of crowdsecurity/crowdsec@909b515798 (2026-09-06). Data as JSON: /api/errors/47d5e8d03a6da9b1. Report an issue: GitHub.

Appendix: source

Thrown at pkg/database/database.go:85

	if config == nil {
		return nil, errors.New("DB config is empty")
	}

	entLogger := logger.WithField("context", "ent")
	entOpt := ent.Log(entLogger.Debug)

	typ, dia, err := config.ConnectionDialect()
	if err != nil {
		return nil, err // unsupported database caught here
	}

	if config.Type == "sqlite" && config.DbPath != ":memory:" {
		/*if it's the first startup, we want to touch and chmod file*/
		if _, err = os.Stat(config.DbPath); os.IsNotExist(err) {
			f, err := os.OpenFile(config.DbPath, os.O_CREATE|os.O_RDWR, 0o600)
			if err != nil {
				return nil, fmt.Errorf("failed to create SQLite database file %q: %w", config.DbPath, err)
			}

			if err := f.Close(); err != nil {
				return nil, fmt.Errorf("failed to create SQLite database file %q: %w", config.DbPath, err)
			}
		}
		// Always try to set permissions to simplify a bit the code for windows (as the permissions set by OpenFile will be garbage)
		if err = setFilePerm(config.DbPath, 0o640); err != nil {
			return nil, fmt.Errorf("unable to set perms on %s: %w", config.DbPath, err)
		}
	}

	dbConnectionString, err := config.ConnectionString()
	if err != nil {
		return nil, fmt.Errorf("failed to generate DB connection string: %w", err)
	}

	drv, err := getEntDriver(typ, dia, dbConnectionString, config)

View on GitHub (pinned to 909b515798)