infiniflow/ragflow · error · ConnectorMissingCredentialError

BigQuery: service_account_json must be a JSON string or obje

Error message

BigQuery: service_account_json must be a JSON string or object

What it means

Type-validation branch in load_credentials: service_account_json exists but is neither a str nor a dict (e.g. a list, int, or nested structure). The connector accepts exactly two shapes — JSON string or mapping — and rejects anything else as a credential error.

Source

Thrown at common/data_source/bigquery_connector.py:163

        """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:
            raise ConnectorMissingCredentialError("BigQuery credentials not loaded.")

        try:
            creds = service_account.Credentials.from_service_account_info(service_account_info)

View on GitHub (pinned to 554fb1133a)

Solutions

  1. Pass the parsed dict, the JSON string, or decode bytes first: raw.decode('utf-8')
  2. Remove accidental list wrapping: use sa_json, not [sa_json]
  3. Add a pre-flight isinstance check in the config loader so the wrong shape is caught at config time

Example fix

# before
creds = {"service_account_json": [sa_dict]}
# or
creds = {"service_account_json": key_file_bytes}

# after
creds = {"service_account_json": sa_dict}
# or
creds = {"service_account_json": key_file_bytes.decode("utf-8")}
Defensive patterns

Strategy: type-guard

Validate before calling

def normalize_sa_input(raw):
    if isinstance(raw, bytes):
        raw = raw.decode("utf-8")
    if isinstance(raw, list) and len(raw) == 1:
        raw = raw[0]  # unwrap accidental list
    if not isinstance(raw, (str, dict)):
        raise TypeError(f"service_account_json must be str|dict, got {type(raw).__name__}")
    return raw

Type guard

def is_sa_json_shape(raw) -> bool:
    return isinstance(raw, (str, dict))

Try / catch

try:
    connector.load_credentials(creds)
except ConnectorMissingCredentialError as e:
    if "must be a JSON string or object" in str(e):
        creds["service_account_json"] = normalize_sa_input(creds["service_account_json"])
        connector.load_credentials(creds)
    else:
        raise

Prevention

When it happens

Trigger: Passing service_account_json as a list (e.g. [sa_dict] accidentally wrapped), an int/bool from a misconfigured form, or bytes (an encoded JSON key file read as b'...') — bytes are not decoded, so they fail this branch.

Common situations: Glue code that wraps the value in a list 'just in case', reading the key file in binary mode and passing bytes, or a config schema that auto-parses JSON into a list structure.

Related errors


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