{"record":{"id":"cbb7a8b8f407aa24","repo":"apache/beam","slug":"secret-name-must-be-specified-in-secret-spec-cbb7a8","errorCode":null,"errorMessage":"Secret name must be specified in secret spec.","messagePattern":"Secret name must be specified in secret spec\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"sdks/python/apache_beam/utils/secret.py","lineNumber":231,"sourceCode":"  @classmethod\n  def from_dict(cls, spec_dict: Dict[str, str]) -> 'GcpSecret':\n    \"\"\"Initialize GcpSecret from a dictionary specification.\"\"\"\n    allowed_keys = {'version_name', 'name', 'project', 'version'}\n    invalid_keys = set(spec_dict.keys()) - allowed_keys\n    if invalid_keys:\n      raise ValueError(\n          f\"Invalid secret parameter {', '.join(sorted(invalid_keys))}\")\n    version_name = cls._parse_version_name(spec_dict)\n    return cls(version_name)\n\n  @classmethod\n  def _parse_version_name(cls, spec_dict: Dict[str, str]) -> str:\n    if \"version_name\" in spec_dict:\n      return spec_dict[\"version_name\"]\n\n    secret_id = spec_dict.get(\"name\")\n    if not secret_id:\n      raise ValueError(\"Secret name must be specified in secret spec.\")\n\n    # Resolve project ID from spec, environment variables, or Application Default Credentials\n    project_id = (\n        spec_dict.get(\"project\") or os.environ.get(\"GOOGLE_CLOUD_PROJECT\") or\n        os.environ.get(\"GCP_PROJECT\"))\n\n    if not project_id:\n      try:\n        import google.auth\n        _, project_id = google.auth.default()\n      except Exception:\n        pass\n\n    version_id = spec_dict.get(\"version\", \"latest\")\n\n    if not project_id:\n      raise ValueError(\n          f\"Could not resolve GCP project ID for secret '{secret_id}'. \"","sourceCodeStart":213,"sourceCodeEnd":249,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/python/apache_beam/utils/secret.py#L213-L249","documentation":"GcpSecret._parse_version_name needs a secret identifier to build the resource path. If the spec has no 'version_name' and the 'name' key is absent or empty, it cannot form a secret ID and raises this ValueError.","triggerScenarios":"GcpSecret.from_dict({'project': 'my-proj'}) or from_dict({'name': ''}) — no 'version_name', and 'name' missing/empty/None.","commonSituations":"Building the secret spec programmatically where the name variable was empty; YAML/JSON config where the name field was omitted; relying on defaults that never set 'name'.","solutions":["Add 'name': '<secret-id>' to the spec dict.","Or supply 'version_name': 'projects/<proj>/secrets/<id>/versions/<ver>' to bypass name/project parsing.","Validate the spec dict is non-empty and has a truthy 'name' before calling from_dict."],"exampleFix":"// before\nGcpSecret.from_dict({'project': 'my-proj'})\n// after\nGcpSecret.from_dict({'project': 'my-proj', 'name': 'db-pass'})","handlingStrategy":"validation","validationCode":"if 'version_name' not in spec and not spec.get('name'):\n    raise ValueError('GcpSecret spec needs name or version_name')","typeGuard":"def has_secret_identity(d) -> bool:\n    return isinstance(d, dict) and (bool(d.get('version_name')) or bool(d.get('name')))","tryCatchPattern":"try:\n    secret = GcpSecret.from_dict(spec)\nexcept ValueError as e:\n    raise ConfigError('secret spec missing name') from e\n","preventionTips":["Check the secret spec at pipeline option parsing time","Avoid building specs from potentially-empty variables","Prefer the fully-qualified 'version_name' form when the name comes from dynamic config"],"tags":["python","apache-beam","secret","missing-field","configuration"],"backgroundTag":"missing-required-argument","analyzedSha":"12126d8942aaf848030c478b4c6a28c6af861c66","analyzedAt":"2026-09-13T01:50:10.254Z","contentChangedAt":"2026-09-13T01:50:10.254Z","schemaVersion":2},"datasetVersion":"2026-09-20T03:17:13.778Z"}