HumanSignal/label-studio · error · ValueError

Google Application Credentials must be valid JSON string. {e

Error message

Google Application Credentials must be valid JSON string. {e}

What it means

get_client caches and builds a google-cloud-storage Client. When google_application_credentials is a string it must be the parsed JSON of a service account; a JSONDecodeError is re-raised as a ValueError telling the user the credentials must be a valid JSON string. Raised for any GCS operation: get_bucket, validate_connection, generate_http_url, get_blob_metadata, validate_pattern.

Source

Thrown at label_studio/io_storages/gcs/utils.py:71

        cls, google_project_id: str = None, google_application_credentials: Union[str, dict] = None
    ) -> gcs.Client:
        """
        :param google_project_id:
        :param google_application_credentials:
        :return:
        """
        google_project_id = google_project_id or GCS.DEFAULT_GOOGLE_PROJECT_ID
        cache_key = google_application_credentials

        if cache_key not in GCS._client_cache:
            # use credentials from LS Cloud Storage settings
            if google_application_credentials:
                if isinstance(google_application_credentials, str):
                    try:
                        google_application_credentials = json.loads(google_application_credentials)
                    except JSONDecodeError as e:
                        # change JSON error to human-readable format
                        raise ValueError(f'Google Application Credentials must be valid JSON string. {e}')
                credentials = service_account.Credentials.from_service_account_info(google_application_credentials)
                GCS._client_cache[cache_key] = gcs.Client(project=google_project_id, credentials=credentials)

            # use Google Application Default Credentials (ADC)
            else:
                GCS._client_cache[cache_key] = gcs.Client(project=google_project_id)

        return GCS._client_cache[cache_key]

    @classmethod
    def validate_connection(
        cls,
        bucket_name: str,
        google_project_id: str = None,
        google_application_credentials: Union[str, dict] = None,
        prefix: str = None,
        use_glob_syntax: bool = False,
    ):

View on GitHub (pinned to 0b49e9b539)

Solutions

  1. Paste/read the actual JSON contents: with open('key.json') as f: creds = f.read(), then pass that string — not the path
  2. If the secret is base64, decode it first: base64 -d key.b64 > key.json and use its contents
  3. Validate the JSON before saving: python -m json.tool key.json; fix truncation/escaping (private_key newlines must survive as \n inside the JSON)
  4. Alternatively unset the credentials field and rely on Application Default Credentials (ADC) on a GCE/GKE instance with a proper service account

Example fix

// before
GOOGLE_APPLICATION_CREDENTIALS=/secrets/key.json  // path -> JSONDecodeError
// after
export GOOGLE_APPLICATION_CREDENTIALS=$(cat /secrets/key.json)  # raw JSON string
# or leave unset and use ADC
Defensive patterns

Strategy: validation

Validate before calling

import json
def credentials_field_ok(creds):
    if not creds:
        return True, 'using ADC'
    try:
        json.loads(creds)
        return True, None
    except json.JSONDecodeError as e:
        return False, str(e)

Type guard

def is_service_account_json(s):
    import json
    try:
        d = json.loads(s) if isinstance(s, str) else s
        return isinstance(d, dict) and d.get('type') == 'service_account' and 'private_key' in d
    except (json.JSONDecodeError, TypeError):
        return False

Try / catch

try:
    client = GCS.get_client(cache_key, google_project_id, google_application_credentials)
except ValueError as e:
    if 'valid JSON string' in str(e):
        logger.error('Read the file contents: creds = open(path).read() — not the path itself')

Prevention

When it happens

Trigger: Setting GOOGLE_APPLICATION_CREDENTIALS (or the storage field) to a file path instead of file contents, to a base64 blob, or to a truncated/corrupted JSON string; environment variable interpolation mangling newlines in the private key.

Common situations: Users copying the credentials file path into the UI field expecting Label Studio to read it; Docker/K8s secret mounted as a path then referenced directly; CI systems that base64-encode secrets; quotes/escaping lost when pasting into the settings form.

Related errors


AI-assisted analysis of HumanSignal/label-studio@0b49e9b539 (2026-08-29). Data as JSON: /api/errors/61ef05a7daa03c78. Report an issue: GitHub.