infiniflow/ragflow · error · ValueError

Invalid JSON in Google Drive credentials

Error message

Invalid JSON in Google Drive credentials

What it means

Raised by get_credentials_from_env after the credential string was found in the environment but json.loads() raised JSONDecodeError. The value must be a complete, valid JSON document (an OAuth token dict or a service-account key file serialized as a string). Common corruption sources are shell quoting damage, trailing junk, or pasting only part of the JSON.

Source

Thrown at common/data_source/google_util/util.py:172

            error,
        )
        results = retrieval_function()
    return results


def get_credentials_from_env(email: str, oauth: bool = False, source="drive") -> dict:
    try:
        if oauth:
            raw_credential_string = os.environ["GOOGLE_OAUTH_CREDENTIALS_JSON_STR"]
        else:
            raw_credential_string = os.environ["GOOGLE_SERVICE_ACCOUNT_JSON_STR"]
    except KeyError:
        raise ValueError("Missing Google Drive credentials in environment variables")

    try:
        credential_dict = json.loads(raw_credential_string)
    except json.JSONDecodeError:
        raise ValueError("Invalid JSON in Google Drive credentials")

    if oauth and source == "drive":
        credential_dict = ensure_oauth_token_dict(credential_dict, DocumentSource.GOOGLE_DRIVE)
    else:
        credential_dict = ensure_oauth_token_dict(credential_dict, DocumentSource.GMAIL)

    refried_credential_string = json.dumps(credential_dict)

    DB_CREDENTIALS_DICT_TOKEN_KEY = "google_tokens"
    DB_CREDENTIALS_DICT_SERVICE_ACCOUNT_KEY = "google_service_account_key"
    DB_CREDENTIALS_PRIMARY_ADMIN_KEY = "google_primary_admin"
    DB_CREDENTIALS_AUTHENTICATION_METHOD = "authentication_method"

    cred_key = DB_CREDENTIALS_DICT_TOKEN_KEY if oauth else DB_CREDENTIALS_DICT_SERVICE_ACCOUNT_KEY

    return {
        cred_key: refried_credential_string,
        DB_CREDENTIALS_PRIMARY_ADMIN_KEY: email,

View on GitHub (pinned to 554fb1133a)

Solutions

  1. Validate the value locally: python -c "import json,os; json.loads(os.environ['GOOGLE_SERVICE_ACCOUNT_JSON_STR'])" and re-export a clean copy until it parses.
  2. Load from the file instead of inline quoting: export GOOGLE_SERVICE_ACCOUNT_JSON_STR="$(cat service_account.json)".
  3. In compose files, use the YAML pipe form or an env_file to avoid quote mangling.
  4. Confirm the string is the JSON document itself, not a base64 blob or a path to the file.

Example fix

# before (shell-mangled JSON)
export GOOGLE_SERVICE_ACCOUNT_JSON_STR="{'type': 'service_account', ...}"  # single quotes -> JSONDecodeError

# after
export GOOGLE_SERVICE_ACCOUNT_JSON_STR="$(cat /secure/service_account.json)"
Defensive patterns

Strategy: validation

Validate before calling

import json, os

def google_env_credentials_valid(oauth: bool) -> bool:
    key = "GOOGLE_OAUTH_CREDENTIALS_JSON_STR" if oauth else "GOOGLE_SERVICE_ACCOUNT_JSON_STR"
    raw = os.environ.get(key)
    if not raw:
        return False
    try:
        return isinstance(json.loads(raw), dict)
    except json.JSONDecodeError:
        return False

Type guard

def is_credential_json(raw) -> bool:
    if not isinstance(raw, str) or not raw.strip():
        return False
    try:
        return isinstance(json.loads(raw), dict)
    except json.JSONDecodeError:
        return False

Try / catch

try:
    creds = get_credentials_from_env(email, oauth=True)
except ValueError as e:
    if 'Invalid JSON' in str(e):
        log.error('Credential env var is corrupt JSON; re-provision from the source JSON file')
        raise
    raise

Prevention

When it happens

Trigger: GOOGLE_SERVICE_ACCOUNT_JSON_STR contains single-quoted pseudo-JSON, a truncated paste, or literal backslash-n sequences from a bad echo. Any call to get_credentials_from_env will hit json.loads and raise this ValueError.

Common situations: Exporting JSON with unescaped quotes in docker-compose YAML; copying the JSON from a web console and losing the closing brace; double-encoding (storing json.dumps(json.dumps(x))); Windows line endings or a BOM prepended by an editor.

Understand the failure class

Related errors


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