ruvnet/ruflo · error · Error

${ENV_ENABLE_FLAG} is set but ${ENV_KEY_VAR} is not. Provide

Error message

${ENV_ENABLE_FLAG} is set but ${ENV_KEY_VAR} is not. Provide a 32-byte key as 64-char hex or 44-char base64. See ADR-096 for keychain/passphrase support (coming in a follow-up).

What it means

Thrown by getKey() when CLAUDE_FLOW_ENCRYPT_AT_REST is set but CLAUDE_FLOW_ENCRYPTION_KEY is not. Encrypt-at-rest is opt-in; enabling it without supplying a key would be unsafe, so the vault refuses rather than generating an ephemeral key that would make existing ciphertext undecryptable after restart. ADR-096 tracks future keychain/passphrase support.

Source

Thrown at v3/@claude-flow/cli/src/encryption/vault.ts:83

 * Resolve a 32-byte encryption key from CLAUDE_FLOW_ENCRYPTION_KEY.
 *
 * Phase 1 supports only the env-var source; keychain and passphrase
 * resolution are deferred to a follow-up iteration (see ADR-096). When
 * encryption is enabled but no key resolves, this throws with a clear
 * message rather than silently falling back to plaintext (fail-closed).
 *
 * Accepted encodings (auto-detected by length):
 *   - 64-char hex (32 bytes)
 *   - 44-char base64 (32 bytes + padding)
 *   - exactly 32 raw bytes (rare; for callers that pre-decode)
 *
 * Anything else is rejected — we'd rather fail loudly than encrypt with a
 * truncated key.
 */
export function getKey(): Buffer {
  const raw = process.env[ENV_KEY_VAR];
  if (!raw) {
    throw new Error(
      `${ENV_ENABLE_FLAG} is set but ${ENV_KEY_VAR} is not. ` +
      `Provide a 32-byte key as 64-char hex or 44-char base64. ` +
      `See ADR-096 for keychain/passphrase support (coming in a follow-up).`,
    );
  }
  return decodeKey(raw);
}

/**
 * Decode a key string. Exposed for testing and for the future passphrase
 * resolver, which will scrypt-derive a Buffer and hand it back through here
 * to share the same length-check.
 */
export function decodeKey(raw: string): Buffer {
  const trimmed = raw.trim();
  // Hex first — strict 64 chars [0-9a-fA-F]
  if (/^[0-9a-fA-F]{64}$/.test(trimmed)) {
    return Buffer.from(trimmed, 'hex');

View on GitHub (pinned to 6b01dc5a68)

Solutions

  1. Generate a 32-byte key and set CLAUDE_FLOW_ENCRYPTION_KEY to its 64-char hex: `node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"`.
  2. Store the key in your secrets manager / .env (NEVER commit it) and ensure it is present in every process that reads or writes ciphertext.
  3. Until you have a key, unset CLAUDE_FLOW_ENCRYPT_AT_REST to disable the feature.

Example fix

# before
CLAUDE_FLOW_ENCRYPT_AT_REST=1
# CLAUDE_FLOW_ENCRYPTION_KEY missing
# after
CLAUDE_FLOW_ENCRYPT_AT_REST=1
CLAUDE_FLOW_ENCRYPTION_KEY=$(node -e "console.log(require('crypto').randomBytes(32).toString('hex'))")
Defensive patterns

Strategy: validation

Validate before calling

function ensureVaultConfigured(): void {
  const enabled = process.env.CLAUDE_FLOW_ENCRYPT_AT_REST;
  const key = process.env.CLAUDE_FLOW_ENCRYPTION_KEY;
  if (enabled && !key) {
    throw new Error('CLAUDE_FLOW_ENCRYPT_AT_REST is set but CLAUDE_FLOW_ENCRYPTION_KEY is not');
  }
}
ensureVaultConfigured();

Type guard

const vaultConfigured = (): boolean =>
  !process.env.CLAUDE_FLOW_ENCRYPT_AT_REST || Boolean(process.env.CLAUDE_FLOW_ENCRYPTION_KEY);

Try / catch

try {
  getKey();
} catch (e) {
  const msg = e instanceof Error ? e.message : String(e);
  if (msg.includes('CLAUDE_FLOW_ENCRYPTION_KEY is not')) {
    console.error('Generate a key: node -e "console.log(crypto.randomBytes(32).toString(\'hex\'))"');
    process.exit(2);
  }
  throw e;
}

Prevention

When it happens

Trigger: Setting CLAUDE_FLOW_ENCRYPT_AT_REST=1 (or any truthy value) in the environment without also setting CLAUDE_FLOW_ENCRYPTION_KEY, or setting it in one process/shell but not the one performing encryption.

Common situations: Configuring encrypt-at-rest in a .env file but forgetting the key line, deploying with a secrets manager that failed to inject the key, or enabling the flag locally to test without yet generating a key.

Related errors


AI-assisted analysis of ruvnet/ruflo@6b01dc5a68 (2026-08-12). Data as JSON: /api/errors/6d8692f72e9bdbf2. Report an issue: GitHub.