apache/pulsar · error

Invalid short topic name '%s', it should be in the format of

Error message

Invalid short topic name '%s', it should be in the format of <tenant>/<namespace>/<topic> or <topic>

What it means

ParseTopicName accepts either a fully qualified topic (persistent://tenant/namespace/topic) or a short topic name (<topic>) which is expanded using the default tenant/namespace. A name with 2 slash-separated segments (e.g. myns/mytopic) fits neither form, so parsing fails with this error.

Source

Thrown at pulsar-function-go/pf/topicName.go:58

	partitionedTopicSuffix = "-partition-"
)

// ParseTopicName parse the given topic name and return TopicName.
func ParseTopicName(topic string) (*TopicName, error) {
	// The topic name can be in two different forms, one is fully qualified topic name,
	// the other one is short topic name
	if !strings.Contains(topic, "://") {
		// The short topic name can be:
		// - <topic>
		// - <tenant>/<namespace>/<topic>
		// - <tenant>/<cluster>/<namespace>/<topic>
		parts := strings.Split(topic, "/")
		if len(parts) == 3 || len(parts) == 4 {
			topic = "persistent://" + topic
		} else if len(parts) == 1 {
			topic = "persistent://" + publicTenant + "/" + defaultNamespace + "/" + parts[0]
		} else {
			return nil, errors.New(
				"Invalid short topic name '" + topic +
					"', it should be in the format of <tenant>/<namespace>/<topic> or <topic>")
		}
	}

	tn := &TopicName{}

	// The fully qualified topic name can be in two different forms:
	// new:    persistent://tenant/namespace/topic
	// legacy: persistent://tenant/cluster/namespace/topic
	parts := strings.SplitN(topic, "://", 2)
	domain := parts[0]
	if domain != "persistent" && domain != "non-persistent" {
		return nil, errors.New("Invalid topic domain: " + domain)
	}
	tn.Domain = domain

	rest := parts[1]

View on GitHub (pinned to 820761864e)

Solutions

  1. Use the full short form: just the topic name, e.g. 'mytopic'
  2. Or use the fully qualified form: 'persistent://public/default/mytopic'
  3. Check the string for stray or missing slashes; 2 segments is always invalid
  4. In Java-interop configs use 'persistent://public/default/<topic>'

Example fix

// before
pf.ParseTopicName("public/mytopic") // error
// after
pf.ParseTopicName("persistent://public/default/mytopic")
Defensive patterns

Strategy: validation

Validate before calling

segments := strings.Count(topic, "/") + 1
if segments != 1 && segments != 3 && segments != 4 {
    return fmt.Errorf("topic %q must have 1, 3, or 4 slash-separated segments", topic)
}

Type guard

func isShortTopic(t string) bool { return !strings.Contains(t, "://") && strings.Count(t, "/") == 0 }

Try / catch

tn, err := pf.ParseTopicName(topic)
if err != nil {
    return fmt.Errorf("parse topic %q: %w", topic, err)
}

Prevention

When it happens

Trigger: Passing a topic like 'public/mytopic' or 'tenant/topic' (2 segments) to setupConsumer or respondMessage; only 1, 3, or 4 segments are valid.

Common situations: Developers supplying tenant/namespace fragments partially, splitting config strings incorrectly, or copying topic names from UI columns that omit the domain prefix.

Related errors


AI-assisted analysis of apache/pulsar@820761864e (2026-09-06). Data as JSON: /api/errors/449f060ea4779c10. Report an issue: GitHub.