infiniflow/ragflow · critical · ValueError

No private key

Error message

No private key

What it means

ValueError raised by decrypt_database_password in common/config_utils.py:113-133. When the service config enables password encryption (encrypt_password: true in service_conf.yaml), database passwords stored in the config are expected to be ciphertext decrypted with a private key configured at base.private_key. If encrypt_password is on but private_key is missing/null, decryption cannot proceed and the loader refuses to continue with a vague 'No private key' error.

Source

Thrown at common/config_utils.py:128

def get_base_config(key, default=None):
    if key is None:
        return None
    if default is None:
        default = os.environ.get(key.upper())
    return CONFIGS.get(key, default)


def decrypt_database_password(password):
    encrypt_password = get_base_config("encrypt_password", False)
    encrypt_module = get_base_config("encrypt_module", False)
    private_key = get_base_config("private_key", None)

    if not password or not encrypt_password:
        return password

    if not private_key:
        raise ValueError("No private key")

    module_fun = encrypt_module.split("#")
    pwdecrypt_fun = getattr(importlib.import_module(module_fun[0]), module_fun[1])

    return pwdecrypt_fun(private_key, password)


def decrypt_database_config(database=None, passwd_key="password", name="database"):
    if not database:
        database = get_base_config(name, {})

    database[passwd_key] = decrypt_database_password(database[passwd_key])
    return database


def update_config(key, value, conf_name=SERVICE_CONF):
    conf_path = conf_realpath(conf_name=conf_name)
    if not os.path.isabs(conf_path):

View on GitHub (pinned to 554fb1133a)

Solutions

  1. Add base.private_key to service_conf.yaml pointing at (or containing) the RSA private key used to encrypt the password.
  2. If you do not actually use encrypted passwords, set encrypt_password: false and store the plaintext DB password (or use environment variables) instead.
  3. Ensure encrypt_module is also set correctly (module#function) — it is required in the very next line once the key check passes.

Example fix

# before (service_conf.yaml)
encrypt_password: true
# no private_key
# after
encrypt_password: true
private_key: "-----BEGIN RSA PRIVATE KEY-----..."
# or, if not using encryption:
# encrypt_password: false
Defensive patterns

Strategy: validation

Validate before calling

from common.config_utils import get_base_config
if get_base_config("encrypt_password", False) and not get_base_config("private_key", None):
    raise RuntimeError("encrypt_password is enabled but private_key is missing — refusing to start")

Try / catch

try:
    decrypt_database_config()
except ValueError as e:
    if str(e) == "No private key":
        # fail fast with an operator-actionable message about base.private_key
        raise RuntimeError("Set base.private_key or disable encrypt_password in service_conf.yaml") from e
    raise

Prevention

When it happens

Trigger: service_conf.yaml (or local.service_conf.yaml) sets encrypt_password: true and supplies an encrypted mysql/password value, but private_key is absent or null. Fires during decrypt_database_config at startup when the DB connection settings are prepared.

Common situations: Copying a production-style config that enables encryption without copying the key; rotating keys and forgetting to update private_key; enabling encrypt_password as an experiment and leaving it on; the key living in a different config stanza than expected.

Related errors


AI-assisted analysis of infiniflow/ragflow@554fb1133a (2026-08-15). Data as JSON: /api/errors/40f3fd185e7f6372. Report an issue: GitHub.