crowdsecurity/crowdsec · critical

unable to init database client: %w

Error message

unable to init database client: %w

What it means

NewServer fails when database.NewClient cannot open/initialize the configured DB backend (sqlite/mysql/postgres). The underlying driver error is wrapped, so the root cause is in the %w chain. It is thrown at startup of the local API server, before any HTTP handler exists.

Source

Thrown at pkg/apiserver/apiserver.go:127

// CustomRecoveryWithWriter returns a middleware for a writer that recovers from any panics and writes a 500 if there was one.
func CustomRecoveryWithWriter(c *gin.Context) {
	defer recoverFromPanic(c)
	c.Next()
}

// NewServer creates a LAPI server.
// It sets up a gin router, a database client, and a controller.
func NewServer(ctx context.Context, config *csconfig.LocalApiServerCfg, accessLogger *log.Entry) (*APIServer, error) {
	var flushScheduler gocron.Scheduler

	if accessLogger == nil {
		accessLogger = log.StandardLogger().WithFields(nil)
	}

	dbClient, err := database.NewClient(ctx, config.DbConfig, config.DbConfig.NewLogger())
	if err != nil {
		return nil, fmt.Errorf("unable to init database client: %w", err)
	}

	if config.DbConfig.Flush != nil {
		flushScheduler, err = dbClient.StartFlushScheduler(ctx, config.DbConfig.Flush)
		if err != nil {
			return nil, err
		}
	}

	if !log.IsLevelEnabled(log.DebugLevel) {
		gin.SetMode(gin.ReleaseMode)
	}

	router := gin.New()

	router.ForwardedByClientIP = false

	// set the remore address of the request to 127.0.0.1 if it comes from a unix socket

View on GitHub (pinned to 909b515798)

Solutions

  1. Run `cscli lapi status` or check crowdsec logs for the wrapped root cause (e.g. dial tcp refused, permission denied).
  2. Verify db_config (type, host, port, user, password, db_path) in config.yaml.
  3. For MySQL/Postgres, test connectivity with mysql/psql using the same credentials.
  4. For SQLite, check the db_path directory exists and is writable by the crowdsec user.
  5. If the DB is corrupted, restore from backup or remove and let crowdsec re-create (`cscli machines` setup will be needed again).

Example fix

// before (config.yaml)
db_config:
  type: sqlite3
  db_path: /nonexistent/crowdsec.db
// after
db_config:
  type: sqlite3
  db_path: /var/lib/crowdsec/data/crowdsec.db
Defensive patterns

Strategy: validation

Validate before calling

// before calling NewServer
if cfg.DbConfig == nil || (cfg.DbConfig.Type == "sqlite3" && cfg.DbConfig.DbPath == "") {
    return fmt.Errorf("db_config is incomplete")
}
if err := pingDatabase(cfg.DbConfig); err != nil {
    return fmt.Errorf("database unreachable: %w", err)
}

Try / catch

srv, err := NewServer(ctx, cfg, nil)
if err != nil {
    if strings.Contains(err.Error(), "unable to init database client") {
        log.Fatalf("DB config/connect problem: %v", err)
    }
    return err
}

Prevention

When it happens

Trigger: Calling NewServer (via initAPIServer/cscli start) with a DbConfig whose DSN/credentials are wrong, the sqlite file path is unwritable, the DB server is down, or migrations fail.

Common situations: Bad db_config in /etc/crowdsec/local_api_credentials.yaml or config.yaml; MySQL/Postgres host unreachable or password changed; SQLite data dir permissions; corrupted SQLite file.

Understand the failure class

Background: Database query failed: Internal Server Error 500s wrapping SQL, Prisma, and connection failures — what to check first — this error's family across 16 libraries.

Related errors


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