zeroclaw-labs/zeroclaw · error

The '{}' backend does not support automatic key generation.

Error message

The '{}' backend does not support automatic key generation. Create the master key externally, then verify access with `zeroclaw quickstart`.

What it means

KeySource::initialize() has a default implementation that errors this way, and only backends that can create key material locally (like the file backend) override it. ZeroClaw calls initialize() during quickstart/provisioning when provisioning_state() reports NeedsInitialization; for externally managed backends (externally provisioned key sources), automatic generation is intentionally unsupported and this default fires. The master key must be created out-of-band, then `zeroclaw quickstart` verifies access to it.

Source

Thrown at crates/zeroclaw-config/src/secrets.rs:74

/// Object-safe, single-trait design.  Only `with_key`, `backend_name`,
/// and `provisioning_state` are required; `initialize` has a default
/// error for backends that cannot create keys locally.
pub trait KeySource: Debug + Send + Sync {
    /// Run `f` with a reference to the 256-bit master key.  The
    /// reference is only valid during the call.
    fn with_key(&self, f: &mut dyn FnMut(&[u8; 32]) -> Result<()>) -> Result<()>;

    /// Human-readable label for diagnostic messages.
    fn backend_name(&self) -> &'static str;

    /// Local-only provisioning check — MUST NOT run scripts or
    /// prompt for user input.
    fn provisioning_state(&self) -> ProvisioningState;

    /// Generate fresh key material.  Default error for backends
    /// that cannot create keys locally.
    fn initialize(&self) -> Result<()> {
        anyhow::bail!(
            "The '{}' backend does not support automatic key generation. \
             Create the master key externally, then verify access with \
             `zeroclaw quickstart`.",
            self.backend_name()
        )
    }
}

/// File-system backed key source.  Reads/writes a 32-byte hex-encoded
/// key at the given path (default: `~/.zeroclaw/.secret_key`, 0600).
#[derive(Debug, Clone)]
pub struct FileKeySource {
    key_path: PathBuf,
}

impl FileKeySource {
    pub fn new(key_path: PathBuf) -> Self {
        Self { key_path }

View on GitHub (pinned to 88bb9c8533)

Solutions

  1. Create/provision the master key externally per your backend's process (e.g., generate 32 random bytes and place them where the backend reads them)
  2. Then run `zeroclaw quickstart` to verify the backend can access the key
  3. If you own the backend and local generation is acceptable, override initialize() in your KeySource impl

Example fix

// before: custom backend relying on default initialize()
impl KeySource for VaultKeySource {
    fn with_key(&self, f: &mut dyn FnMut(&[u8; 32]) -> Result<()>) -> Result<()> { /* ... */ }
    fn backend_name(&self) -> &'static str { "vault" }
    fn provisioning_state(&self) -> ProvisioningState { ProvisioningState::NeedsInitialization }
}

// after: implement local generation
impl KeySource for VaultKeySource {
    fn initialize(&self) -> Result<()> {
        let key: [u8; 32] = rand::random();
        self.store_key(&key) // backend-specific write
    }
    // ...same remaining methods
}
Defensive patterns

Strategy: type-guard

Validate before calling

use zeroclaw_config::secrets::ProvisioningState;
fn can_auto_initialize(src: &dyn KeySource) -> bool {
    // Only attempt initialize() when the backend says local init is expected;
    // ExternallyProvisioned backends reject it by design.
    matches!(src.provisioning_state(), ProvisioningState::NeedsInitialization)
}

Type guard

fn needs_local_init(state: ProvisioningState) -> bool {
    matches!(state, ProvisioningState::NeedsInitialization)
}

if needs_local_init(source.provisioning_state()) {
    source.initialize()?; // safe: backend opted into local generation
}

Try / catch

if let Err(e) = source.initialize() {
    if e.to_string().contains("does not support automatic key generation") {
        eprintln!("provision the master key externally, then run `zeroclaw quickstart`");
    }
    return Err(e);
}

Prevention

When it happens

Trigger: Programmatically calling KeySource::initialize() on a custom or external backend that does not override the default; running a provisioning/quickstart flow against a key source whose material lives outside this process (KMS, secret manager, operator-managed file); treating ExternallyProvisioned like NeedsInitialization and calling initialize().

Common situations: Writing a custom KeySource (e.g., vault or HSM backed) and forgetting to implement initialize(); deployment automation calling initialize() unconditionally on all backends; org policy forbidding locally generated keys, hitting the deliberate refusal.

Related errors


AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23). Data as JSON: /api/errors/53e89c06cf019a4f. Report an issue: GitHub.