crowdsecurity/crowdsec · error

get scenario in db: %w

Error message

get scenario in db: %w

What it means

Authenticate, called by NewAPIC during startup, refreshes the watcher token when none is usable. Before calling CAPI it fetches the machine list to aggregate scenarios; a failure there is wrapped as 'get scenario in db'. This is a startup-blocking error: the watcher cannot authenticate to CAPI.

Source

Thrown at pkg/apiserver/apic.go:270

//
// If a new token is obtained, it is saved back to the database for caching.
func (a *apic) Authenticate(ctx context.Context, config *csconfig.OnlineApiClientCfg) error {
	transport := a.apiClient.GetClient().Transport.(*apiclient.JWTTransport)

	token, err := a.dbClient.LoadAPICToken(ctx, log.StandardLogger())
	if err == nil {
		log.Debug("using valid token from DB")
		transport.Token = token.Raw
		transport.Expiration = token.ExpiresAt

		return nil
	}

	log.WithError(err).Debug("No useful token, authenticating")

	scenarios, err := a.FetchScenariosListFromDB(ctx)
	if err != nil {
		return fmt.Errorf("get scenario in db: %w", err)
	}

	password := strfmt.Password(config.Credentials.Password)

	authResp, _, err := a.apiClient.Auth.AuthenticateWatcher(ctx, models.WatcherAuthRequest{
		MachineID: &config.Credentials.Login,
		Password:  &password,
		Scenarios: scenarios,
	})
	if err != nil {
		return fmt.Errorf("authenticate watcher (%s): %w", config.Credentials.Login, err)
	}

	if err = transport.Expiration.UnmarshalText([]byte(authResp.Expire)); err != nil {
		return fmt.Errorf("unable to parse jwt expiration: %w", err)
	}

	transport.Token = authResp.Token

View on GitHub (pinned to 909b515798)

Solutions

  1. Verify the local DB works: run cscli machines list (same ListMachines path)
  2. Check DB config and backend availability; restore connectivity or fix credentials
  3. Ensure schema migrations ran (restart crowdsec / cscli db migrate equivalent)
  4. Restore crowdsec.db from backup or re-register the watcher (cscli machines add / capi register) if unrecoverable
Defensive patterns

Strategy: try-catch

Validate before calling

// before authenticating, sanity-check DB access
if _, err := dbClient.ListMachines(ctx); err != nil {
	return fmt.Errorf("local DB not readable: %w", err)
}

Try / catch

scenarios, err := a.FetchScenariosListFromDB(ctx)
if err != nil {
	return fmt.Errorf("get scenario in db: %w", err)
}
// caller: inspect with errors.As for sql/sqlite errors and decide whether to retry or fail startup

Prevention

When it happens

Trigger: a.FetchScenariosListFromDB(ctx) returns an error during the authenticate flow — i.e. the underlying ListMachines DB call fails (unreachable backend, missing/corrupt machines table, migration pending).

Common situations: crowdsec.db deleted or corrupted on a machine with existing CAPI enrollment; DB backend (Postgres/MySQL) down or credentials rotated; upgrade without schema migration; read-only mount under /var/lib/crowdsec/data.

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/0a90d14dc4e000bd. Report an issue: GitHub.