infiniflow/ragflow · error · ConnectorMissingCredentialError

BigQuery: service_account_json is not valid JSON: {exc}

Error message

BigQuery: service_account_json is not valid JSON: {exc}

What it means

Raised when service_account_json is supplied as a string but json.loads fails — the string is not valid JSON. The JSONDecodeError detail is embedded, and the error type is ConnectorMissingCredentialError (credential material unusable, treated as a credential problem).

Source

Thrown at common/data_source/bigquery_connector.py:159

    # ------------------------------------------------------------------ #
    # Credentials & client
    # ------------------------------------------------------------------ #
    def load_credentials(self, credentials: Dict[str, Any]) -> Dict[str, Any] | None:
        """Load BigQuery service-account credentials.

        Accepts ``service_account_json`` as either a dict or a JSON string.
        """
        logging.debug("Loading credentials for BigQuery project: %s", self.project_id)

        raw = (credentials or {}).get("service_account_json")
        if not raw:
            raise ConnectorMissingCredentialError("BigQuery: missing service_account_json")

        if isinstance(raw, str):
            try:
                service_account_info = json.loads(raw)
            except json.JSONDecodeError as exc:
                raise ConnectorMissingCredentialError(f"BigQuery: service_account_json is not valid JSON: {exc}")
        elif isinstance(raw, dict):
            service_account_info = raw
        else:
            raise ConnectorMissingCredentialError("BigQuery: service_account_json must be a JSON string or object")

        self._credentials = {"service_account_info": service_account_info}
        return None

    def _get_client(self):
        """Create and cache a BigQuery client from the loaded service account."""
        if self._client is not None:
            return self._client

        if bigquery is None or service_account is None:
            raise ConnectorValidationError("BigQuery client not installed. Please install google-cloud-bigquery.")

        service_account_info = self._credentials.get("service_account_info")
        if not service_account_info:

View on GitHub (pinned to 554fb1133a)

Solutions

  1. Re-download the service account JSON key from GCP and pass its full contents verbatim
  2. If building the string from a dict in code, use json.dumps(obj) — never str(obj)/repr(obj)
  3. Check the embedded JSONDecodeError position to see where parsing broke (usually truncation)
  4. If the value came through an env var, verify no shell quoting mangled it (print len() and first/last chars)

Example fix

# before
creds = {"service_account_json": str(sa_dict)}  # repr, not JSON

# after
import json
creds = {"service_account_json": json.dumps(sa_dict)}
# or simply pass the dict directly
creds = {"service_account_json": sa_dict}
Defensive patterns

Strategy: validation

Validate before calling

import json
def normalize_sa_json(raw) -> dict:
    if isinstance(raw, dict):
        return raw
    if isinstance(raw, str):
        return json.loads(raw)  # raises JSONDecodeError here with a clear stack
    raise TypeError("service_account_json must be str or dict")

Type guard

def is_parseable_sa_json(raw) -> bool:
    if isinstance(raw, dict):
        return True
    if isinstance(raw, str):
        try:
            json.loads(raw)
            return True
        except json.JSONDecodeError:
            return False
    return False

Try / catch

try:
    connector.load_credentials(creds)
except ConnectorMissingCredentialError as e:
    if "not valid JSON" in str(e):
        raise ConfigError("re-paste the full key file; JSON was truncated or repr'd") from e
    raise

Prevention

When it happens

Trigger: Passing service_account_json as a string that is not parseable JSON: truncated key file, Python-repr dict string ("{'type': ...}" with single quotes), a value with a BOM or stray characters, or newlines introduced by env-var encoding.

Common situations: Pasting the key file into an env var with wrapping/truncation, double-encoding (the JSON string was serialized again), or using repr(dict) instead of json.dumps(dict) in glue code.

Related errors


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