crewAIInc/crewAI · critical · RuntimeError

Failed to create or read encryption key

Error message

Failed to create or read encryption key

What it means

Raised by TokenManager._get_or_create_key after three attempts fail: reading an existing secret.key returned None or a value whose length is not 44 bytes (Fernet key length), atomically creating a new key file failed, and re-reading still failed. This means the key storage location is unwritable or unreadable — permissions, read-only filesystem, full disk, or a corrupt existing secret.key of the wrong size.

Source

Thrown at lib/crewai-core/src/crewai_core/token_manager.py:48

        self.fernet = Fernet(self.key)

    def _get_or_create_key(self) -> bytes:
        """Get or create the encryption key."""
        key_filename: str = "secret.key"

        key = self._read_secure_file(key_filename)
        if key is not None and len(key) == _FERNET_KEY_LENGTH:
            return key

        new_key = Fernet.generate_key()
        if self._atomic_create_secure_file(key_filename, new_key):
            return new_key

        key = self._read_secure_file(key_filename)
        if key is not None and len(key) == _FERNET_KEY_LENGTH:
            return key

        raise RuntimeError("Failed to create or read encryption key")

    def save_tokens(self, access_token: str, expires_at: int) -> None:
        """Save the access token and its expiration time.

        Args:
            access_token: The access token to save.
            expires_at: The UNIX timestamp of the expiration time.
        """
        expiration_time = datetime.fromtimestamp(expires_at)
        data = {
            "access_token": access_token,
            "expiration": expiration_time.isoformat(),
        }
        encrypted_data = self.fernet.encrypt(json.dumps(data).encode())
        self._atomic_write_secure_file(self.file_path, encrypted_data)

    def get_token(self) -> str | None:
        """Return the access token if valid and not expired, else None."""

View on GitHub (pinned to 754d7323be)

Solutions

  1. Check write permission on the directory where secret.key is stored and chown/chmod it for the running user.
  2. If secret.key exists but is corrupt, back it up and delete it so a fresh 44-byte key can be created (note: tokens encrypted with the old key become unrecoverable).
  3. On read-only filesystems, point the storage to a writable location or run as a user with write access.
  4. Free disk space if the atomic create is failing due to ENOSPC.

Example fix

# before: config dir owned by root, process runs as app user
# chown -R appuser ~/.config/crewai

# after: verify writability before constructing
from pathlib import Path
key_dir = Path.home() / ".config" / "crewai"
key_dir.mkdir(parents=True, exist_ok=True)
assert os.access(key_dir, os.W_OK), f"no write access to {key_dir}"
tm = TokenManager()
Defensive patterns

Strategy: try-catch

Validate before calling

import os
from pathlib import Path

def key_store_writable() -> bool:
    d = Path(".")  # directory where secret.key is stored
    return os.access(d, os.W_OK | os.R_OK)

Try / catch

try:
    tm = TokenManager()
except RuntimeError as e:
    if "encryption key" in str(e):
        # fix permissions on the key directory / remove corrupt secret.key, then retry once after remediation
        ...

Prevention

When it happens

Trigger: Instantiating TokenManager(...) when (a) secret.key exists but is truncated/corrupt (len != 44), and (b) _atomic_create_secure_file cannot replace it because the directory is read-only, owned by another user, or the disk is full; also in sandboxes that deny writes to the key directory.

Common situations: Running the CLI in Docker/CI as a user without write access to the config dir; a partially-written key from a killed process; NFS/home-dir quota issues; running with a read-only mounted config directory.

Related errors


AI-assisted analysis of crewAIInc/crewAI@754d7323be (2026-08-15). Data as JSON: /api/errors/121f3371745a085c. Report an issue: GitHub.