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
- 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)
- Then run `zeroclaw quickstart` to verify the backend can access the key
- 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
- Always branch on provisioning_state() (Initialized / NeedsInitialization / ExternallyProvisioned) instead of calling initialize() blindly
- When implementing custom KeySource backends, override initialize() only if local generation is genuinely supported
- Document for each deployment backend whether keys are self-managed or externally provisioned
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
- Key file path is a symlink — refusing to write
- Cannot determine current username; ACL hardening is required
- Failed to take ownership of key file via takeown; cannot est
- Failed to set restrictive ACL via icacls; key file permissio
- Hex string has odd length
AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23).
Data as JSON: /api/errors/53e89c06cf019a4f.
Report an issue: GitHub.