apache/beam · error · TypeError

Secret 'spec' must be a string, got

Error message

Secret 'spec' must be a string, got {type(spec).__name__}

What it means

Secret.from_json builds a Secret from a JSON spec string plus a secret manager name. Because the spec must be parseable JSON text, a non-str spec (dict, bytes, None) raises TypeError naming the actual type received.

Solutions

  1. Serialize the spec: Secret.from_json(json.dumps(param_map), secret_manager)
  2. Ensure the value is not None before calling (check upstream parsing)
  3. If you have a dict, use parse_secret_option or json.dumps first

Example fix

// before
Secret.from_json({'name': 'my-secret'}, 'GoogleCloudSecretManager')
// after
import json
Secret.from_json(json.dumps({'name': 'my-secret'}), 'GoogleCloudSecretManager')
Defensive patterns

Strategy: type-guard

Validate before calling

if not isinstance(spec, str):
    raise TypeError(f'spec must be a JSON string, got {type(spec).__name__}')

Type guard

def is_str_spec(spec):
    return isinstance(spec, str)

Try / catch

try:
    secret = Secret.from_json(spec, secret_manager)
except TypeError as e:
    logging.error('bad spec type: %s', e)
    secret = Secret.from_json(json.dumps(spec), secret_manager)  # if spec is a dict

Prevention

When it happens

Trigger: Calling from_json with a dict (e.g. {'name': ...}) instead of json.dumps of it, or with None/bytes when wiring parameters through parse_secret_option.

Common situations: Passing an already-parsed dict from YAML config; API change where callers used to accept dicts; forgetting json.dumps when constructing the spec.

Understand the failure class

Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.

Related errors


AI-assisted analysis of apache/beam@12126d8942 (2026-09-13). Data as JSON: /api/errors/d429ec6fba77b0ab. Report an issue: GitHub.

Appendix: source

Thrown at sdks/python/apache_beam/utils/secret.py:128

          f'Invalid secret type {secret_type}, currently only '
          'GcpSecret and GcpHsmGeneratedSecret are supported')

    return cls.from_json(json.dumps(param_map), secret_manager)

  @classmethod
  def from_json(
      cls, spec: str, secret_manager: Optional[str] = None) -> 'Secret':
    """Return a Secret instance based on secret_manager provider and secret specification.

    Args:
      spec: Secret string (raw secret or JSON specification string).
      secret_manager: Secret manager string (e.g. 'GoogleCloudSecretManager').

    Returns:
      An instance of Secret.
    """
    if not isinstance(spec, str):
      raise TypeError(
          f"Secret 'spec' must be a string, got {type(spec).__name__}")

    secret_manager_name = (
        secret_manager.strip()
        if secret_manager and secret_manager.strip() else None)

    spec_dict = None
    try:
      spec_dict = json.loads(spec)
      if not isinstance(spec_dict, dict):
        spec_dict = None
    except Exception:
      try:
        import ast
        spec_dict = ast.literal_eval(spec)
        if not isinstance(spec_dict, dict):
          spec_dict = None
      except Exception:

View on GitHub (pinned to 12126d8942)