crowdsecurity/crowdsec · critical

failed to create SQLite database file %q: %w

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).

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)

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.