{"record":{"id":"393a83b15ceab3c1","repo":"apache/beam","slug":"invalid-pubsub-project-name-r","errorCode":null,"errorMessage":"Invalid PubSub project name: %r.","messagePattern":"Invalid PubSub project name: %r\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"sdks/python/apache_beam/io/gcp/pubsub.py","lineNumber":494,"sourceCode":"            self.publish_with_ordering_key,\n            label='Publish With Ordering Key').drop_if_none(),\n    }\n\n\nPROJECT_ID_REGEXP = '[a-z][-a-z0-9:.]{4,61}[a-z0-9]'\nSUBSCRIPTION_REGEXP = 'projects/([^/]+)/subscriptions/(.+)'\nTOPIC_REGEXP = 'projects/([^/]+)/topics/(.+)'\n\n\ndef parse_topic(full_topic: str) -> tuple[str, str]:\n  match = re.match(TOPIC_REGEXP, full_topic)\n  if not match:\n    raise ValueError(\n        'PubSub topic must be in the form \"projects/<project>/topics'\n        '/<topic>\" (got %r).' % full_topic)\n  project, topic_name = match.group(1), match.group(2)\n  if not re.match(PROJECT_ID_REGEXP, project):\n    raise ValueError('Invalid PubSub project name: %r.' % project)\n  return project, topic_name\n\n\ndef parse_subscription(full_subscription):\n  match = re.match(SUBSCRIPTION_REGEXP, full_subscription)\n  if not match:\n    raise ValueError(\n        'PubSub subscription must be in the form \"projects/<project>'\n        '/subscriptions/<subscription>\" (got %r).' % full_subscription)\n  project, subscription_name = match.group(1), match.group(2)\n  if not re.match(PROJECT_ID_REGEXP, project):\n    raise ValueError('Invalid PubSub project name: %r.' % project)\n  return project, subscription_name\n\n\n# TODO(BEAM-27443): Remove (or repurpose as a proper PTransform).\nclass _PubSubSource(iobase.SourceBase):\n  \"\"\"Source for a Cloud Pub/Sub topic or subscription.","sourceCodeStart":476,"sourceCodeEnd":512,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/python/apache_beam/io/gcp/pubsub.py#L476-L512","documentation":"After the topic path shape matches, parse_topic validates the extracted project segment against PROJECT_ID_REGEXP. A ValueError is raised when the project component of projects/<project>/topics/<topic> is not a valid GCP project id.","triggerScenarios":"Topics strings like 'projects/My_Project!/topics/t' or 'projects//topics/t' (empty project) where the project segment contains characters outside GCP project-id rules (6-30 chars, lowercase letters, digits, hyphens, must start with a letter).","commonSituations":"Typos in the project id; embedding an uppercase project name or numeric project number where a project id is expected; empty project due to malformed path.","solutions":["Use the canonical lowercase project id (not project number or display name) in the topic path","Verify with re.match against GCP project id rules before constructing the sink","Fetch the correct project id via `gcloud config get-value project`"],"exampleFix":"// before\nWriteToPubSub(topic='projects/MyProject123!/topics/t')\n// after\nWriteToPubSub(topic='projects/myproject123/topics/t')","handlingStrategy":"validation","validationCode":"import re\nproj = topic.split('/')[1]\nassert re.match(r'[a-z][-a-z0-9]{4,28}[a-z0-9]', proj), f'bad project id: {proj!r}'","typeGuard":null,"tryCatchPattern":"try:\n    beam.io.WriteToPubSub(topic=topic)\nexcept ValueError as e:\n    if 'Invalid PubSub project name' in str(e):\n        raise SystemExit(f'Fix project in topic path: {e}')","preventionTips":["Use lowercase project ids, never project numbers or display names","Validate project ids at config load time","Echo the resolved topic path in pipeline logs for review"],"tags":["python","pubsub","validation","apache-beam"],"backgroundTag":"invalid-identifier-format","analyzedSha":"12126d8942aaf848030c478b4c6a28c6af861c66","analyzedAt":"2026-09-13T01:50:10.254Z","contentChangedAt":"2026-09-13T01:50:10.254Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}