caddyserver/caddy · error

configuring ACME DB: %v

Error message

configuring ACME DB: %v

What it means

Returned when the smallstep ACME nosql layer (acmeNoSQL.New over the CA's bbolt database) fails to initialize its table schema on the ACME database. This happens during provisioning of the `acme_server` handler, after the authority is created. The %v wraps the underlying nosql/bbolt error (usually file open, permissions, or corruption).

Source

Thrown at modules/caddypki/acmeserver/acmeserver.go:197

					Claims: &provisioner.Claims{
						MinTLSDur:     &provisioner.Duration{Duration: 5 * time.Minute},
						MaxTLSDur:     &provisioner.Duration{Duration: 24 * time.Hour * 365},
						DefaultTLSDur: &provisioner.Duration{Duration: time.Duration(ash.Lifetime)},
					},
				},
			},
		},
		DB: database,
	}

	ash.acmeAuth, err = ca.NewAuthority(authorityConfig)
	if err != nil {
		return err
	}

	ash.acmeDB, err = acmeNoSQL.New(ash.acmeAuth.GetDatabase().(nosql.DB))
	if err != nil {
		return fmt.Errorf("configuring ACME DB: %v", err)
	}

	ash.acmeClient, err = ash.makeClient()
	if err != nil {
		return err
	}

	ash.acmeLinker = acme.NewLinker(
		ash.Host,
		strings.Trim(ash.PathPrefix, "/"),
	)

	// extract its http.Handler so we can use it directly
	r := chi.NewRouter()
	r.Route(ash.PathPrefix, func(r chi.Router) {
		api.Route(r)
	})
	ash.acmeEndpoints = r

View on GitHub (pinned to 50e54ee279)

Solutions

  1. Check the wrapped cause — bbolt errors like `timeout` indicate the file is locked by another process; find and stop it
  2. Verify write permissions on the storage path returned by `caddy list-modules`/AppDataDir (typically ~/.local/share/caddy/acme_server/<ca-id>/)
  3. If the db file is corrupt and the CA data is expendable, stop Caddy, remove the acme_server/<key> folder (clients must re-enroll), and restart
  4. Ensure only one Caddy instance uses the same data dir

Example fix

# before: read-only volume mount
docker run -v /caddy-data:/data:ro caddy

# after: writable mount
docker run -v /caddy-data:/data caddy
Defensive patterns

Strategy: retry

Validate before calling

// Pre-flight the database path before provisioning the handler:
dir := filepath.Join(caddy.AppDataDir(), "acme_server", key)
if f, err := os.OpenFile(filepath.Join(dir, "db"), os.O_RDWR, 0o600); err != nil {
    return fmt.Errorf("acme db not writable: %w", err)
} else { f.Close() }

Try / catch

// On provisioning failure, distinguish lock contention (retryable) from corruption (not):
if err := ash.provision(); err != nil {
    if strings.Contains(err.Error(), "timeout") || strings.Contains(err.Error(), "locked") {
        time.Sleep(time.Second) // then retry once with backoff
    } else {
        return err // corrupt db / permissions: needs manual intervention
    }
}

Prevention

When it happens

Trigger: Two `acme_server` handlers pointed at the same CA but racing to init the DB during overlapping config loads; the data dir file ($AppDataDir/acme_server/<key>/db) is corrupt, truncated, or locked by another process; disk full or read-only filesystem where bbolt cannot create/open the file.

Common situations: Running Caddy in a container with the data dir on a read-only volume or a volume that lost data mid-write; migrating data dirs between Caddy versions; another Caddy instance or a leftover process holding a flock on the bbolt file; a previously killed Caddy leaving a torn db file.

Related errors


AI-assisted analysis of caddyserver/caddy@50e54ee279 (2026-08-15). Data as JSON: /api/errors/4f0823f45ba42f5f. Report an issue: GitHub.