apache/beam · error · IllegalArgumentException

Pubsub topic is not in projects/

Error message

Pubsub topic is not in projects/<project_id>/topics/<topic_name> format: {path}

What it means

PubsubIO.Read.fromPath requires the topic path to match projects/<project_id>/topics/<topic_name>. If neither the modern nor legacy v1beta1 pattern matches TOPIC_REGEXP, this IllegalArgumentException is thrown describing the expected format.

Solutions

  1. Use the fully qualified path: projects/YOUR_PROJECT/topics/YOUR_TOPIC.
  2. Confirm you aren't passing a subscription path to fromTopic (use fromSubscription instead).
  3. Build the path programmatically: String.format("projects/%s/topics/%s", projectId, topicId).

Example fix

// before
PubsubIO.readStrings().fromTopic("events");
// after
PubsubIO.readStrings().fromTopic("projects/my-project/topics/events");
Defensive patterns

Strategy: validation

Validate before calling

static void checkTopicPath(String path) {
  if (!path.matches("projects/[a-zA-Z0-9-_.~%+]+/topics/[a-zA-Z0-9-_.~%+]+"))
    throw new IllegalArgumentException("Expected projects/<proj>/topics/<name>: " + path);
}

Type guard

boolean isTopicPath(String p) {
  return p != null && p.matches("projects/[^/]+/topics/[^/]+");
}

Try / catch

try {
  return PubsubIO.readStrings().fromTopic(topic);
} catch (IllegalArgumentException e) {
  if (e.getMessage().contains("topics/<topic_name> format"))
    throw new ConfigException("Topic path must be projects/<proj>/topics/<name>, got: " + topic, e);
  throw e;
}

Prevention

When it happens

Trigger: Calling PubsubIO.read...().fromTopic()/fromPath with a bare topic name ("mytopic"), a subscription path (projects/p/subscriptions/s), or a malformed path.

Common situations: Passing only the topic short name from configuration; accidentally passing the subscription path to fromTopic; typos in the 'topics' segment.

Understand the failure class

Background: "Invalid URL" errors: why new URL(), URI.parse, and reqwest::Url reject your string — missing scheme, whitespace, and bad path format — this error's family across 39 libraries.

Related errors


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

Appendix: source

Thrown at sdks/java/io/google-cloud-platform/src/main/java/org/apache/beam/sdk/io/gcp/pubsub/PubsubIO.java:483

     */
    public static PubsubTopic fromPath(String path) {
      if (path.equals(TOPIC_DEV_NULL_TEST_NAME)) {
        return new PubsubTopic(PubsubTopic.Type.FAKE, "", path);
      }

      String projectName, topicName;

      Matcher v1beta1Match = V1BETA1_TOPIC_REGEXP.matcher(path);
      if (v1beta1Match.matches()) {
        LOG.warn(
            "Saw topic in v1beta1 format.  Topics should be in the format "
                + "projects/<project_id>/topics/<topic_name>");
        projectName = v1beta1Match.group(1);
        topicName = v1beta1Match.group(2);
      } else {
        Matcher match = TOPIC_REGEXP.matcher(path);
        if (!match.matches()) {
          throw new IllegalArgumentException(
              "Pubsub topic is not in projects/<project_id>/topics/<topic_name> format: " + path);
        }
        projectName = match.group(1);
        topicName = match.group(2);
      }

      projectName =
          checkArgumentNotNull(
              projectName, "Invalid path: project name must be non-null: %s", path);
      topicName =
          checkArgumentNotNull(topicName, "Invalid path: topic name must be non-null: %s", path);

      validateProjectName(projectName);
      validatePubsubName(topicName);
      return new PubsubTopic(PubsubTopic.Type.NORMAL, projectName, topicName);
    }

    /**

View on GitHub (pinned to 12126d8942)