{"record":{"id":"063989d88d00f5de","repo":"apache/beam","slug":"pubsub-subscription-must-be-in-the-form-projects-project","errorCode":null,"errorMessage":"PubSub subscription must be in the form \"projects/<project>/subscriptions/<subscription>\" (got %r).","messagePattern":"PubSub subscription must be in the form \"projects/<project>/subscriptions/<subscription>\" \\(got %r\\)\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"sdks/python/apache_beam/io/gcp/pubsub.py","lineNumber":501,"sourceCode":"TOPIC_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.\n\n  This ``NativeSource`` is overridden by a native Pubsub implementation.\n\n  Attributes:\n    with_attributes: If False, will fetch just message data. Otherwise,\n      fetches ``PubsubMessage`` protobufs.\n  \"\"\"","sourceCodeStart":483,"sourceCodeEnd":519,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/python/apache_beam/io/gcp/pubsub.py#L483-L519","documentation":"parse_subscription validates that a Pub/Sub subscription string matches the SUBSCRIPTION_REGEXP form projects/<project>/subscriptions/<subscription>. A ValueError is raised when the string does not match this fully-qualified shape.","triggerScenarios":"Calling ReadFromPubSub with subscription='my-sub' or 'projects/p/subscriptions/' (empty name), or passing a topic path where a subscription is expected.","commonSituations":"Copying only the subscription id from the console; mixing up topic vs subscription argument; older code using short names from a pre-validation Beam version.","solutions":["Pass the fully-qualified subscription: 'projects/my-project/subscriptions/my-sub'","Build the string from parts: f'projects/{project}/subscriptions/{subscription}'","Confirm you passed it to the `subscription=` parameter, not `topic=`"],"exampleFix":"// before\nReadFromPubSub(subscription='my-sub')\n// after\nReadFromPubSub(subscription='projects/my-gcp-project/subscriptions/my-sub')","handlingStrategy":"validation","validationCode":"import re\nassert re.match(r'projects/([^/]+)/subscriptions/(.+)', sub), f'bad subscription: {sub!r}'","typeGuard":null,"tryCatchPattern":"try:\n    beam.io.ReadFromPubSub(subscription=sub)\nexcept ValueError as e:\n    if 'PubSub subscription must be in the form' in str(e):\n        sub = f'projects/{PROJECT}/subscriptions/{sub_name}'\n    else:\n        raise","preventionTips":["Always use fully-qualified subscription paths","Distinguish topic vs subscription config keys clearly","Strip trailing slashes from user-supplied paths"],"tags":["python","pubsub","validation","apache-beam"],"backgroundTag":"invalid-argument-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"}