crowdsecurity/crowdsec · error

unable to set perms on

Error message

unable to set perms on %s: %w

What it means

After creating the SQLite file, NewClient calls setFilePerm(db_path, 0640) and wraps any failure as `unable to set perms on <path>`. On Unix this is os.Chmod/chown-style enforcement; on Windows permission semantics differ, which is why the code always attempts it. Startup aborts on failure.

Solutions

  1. chown the database file and its directory to the user crowdsec runs as (sudo chown crowdsec:crowdsec /var/lib/crowdsec/data/crowdsec.db)
  2. Remove immutable attributes (chattr -i) or move the data dir off restricted filesystems
  3. Delete the pre-existing file (backup first) so it's recreated by the correct user
  4. Check mount options (read-only) and MAC-policy denials

Example fix

// before
-rw------- root root /var/lib/crowdsec/data/crowdsec.db   # created by sudo run
// after
sudo chown crowdsec:crowdsec /var/lib/crowdsec/data/crowdsec.db
sudo chmod 640 /var/lib/crowdsec/data/crowdsec.db
Defensive patterns

Strategy: validation

Validate before calling

info, err := os.Stat(dbPath)
if err == nil && info.Mode().Perm()&0o200 == 0 {
	log.Fatalf("db file not writable by %s", os.Geteuid())
}

Prevention

When it happens

Trigger: chmod fails because the process doesn't own the file (created previously by root, now running as the crowdsec user), read-only filesystem, or unsupported/failed permission operation on exotic filesystems (Windows ACLs, FUSE).

Common situations: First run executed with sudo and later runs as service user who can't chmod a root-owned file; Docker volume with mismatched UID; immutable flag set on the file.

Understand the failure class

Background: Permission denied / not authorized / 403 Forbidden: access-control rejections when the caller lacks the required role, grant, or ownership — this error's family across 18 libraries.

Related errors


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

Appendix: source

Thrown at pkg/database/database.go:94

	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)
	if err != nil {
		return nil, fmt.Errorf("failed opening connection to %s: %w", config.Type, err)
	}

	client = ent.NewClient(ent.Driver(drv), entOpt)

	if config.LogLevel >= log.DebugLevel {
		logger.Debugf("Enabling request debug")

View on GitHub (pinned to 909b515798)