{"record":{"id":"346b0947b0ca3945","repo":"apache/pulsar","slug":"invalid-topic-name-s","errorCode":null,"errorMessage":"Invalid topic name: %s","messagePattern":"Invalid topic name: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pulsar-function-go/pf/topicName.go","lineNumber":93,"sourceCode":"\n\trest := parts[1]\n\tvar err error\n\n\t// The rest of the name can be in different forms:\n\t// new:    tenant/namespace/<localName>\n\t// legacy: tenant/cluster/namespace/<localName>\n\t// Examples of localName:\n\t// 1. some/name/xyz//\n\t// 2. /xyz-123/feeder-2\n\tparts = strings.SplitN(rest, \"/\", 4)\n\tif len(parts) == 3 {\n\t\t// New topic name without cluster name\n\t\ttn.Namespace = parts[0] + \"/\" + parts[1]\n\t} else if len(parts) == 4 {\n\t\t// Legacy topic name that includes cluster name\n\t\ttn.Namespace = fmt.Sprintf(\"%s/%s/%s\", parts[0], parts[1], parts[2])\n\t} else {\n\t\treturn nil, errors.New(\"Invalid topic name: \" + topic)\n\t}\n\n\ttn.Name = topic\n\ttn.Partition, err = getPartitionIndex(topic)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn tn, nil\n}\n\n// NameWithoutPartition returns the topic name, sans the partition portion\nfunc (tn *TopicName) NameWithoutPartition() string {\n\tif tn.Partition < 0 {\n\t\treturn tn.Name\n\t}\n\tidx := strings.LastIndex(tn.Name, partitionedTopicSuffix)\n\tif idx > 0 {","sourceCodeStart":75,"sourceCodeEnd":111,"githubUrl":"https://github.com/apache/pulsar/blob/820761864ed8e2a7d2e52dd9763ad2ae117c1395/pulsar-function-go/pf/topicName.go#L75-L111","documentation":"After expanding the domain, ParseTopicName splits the rest of the topic by '/'. Valid names have 3 parts (tenant/namespace/topic) or 4 (legacy tenant/cluster/namespace/topic). Anything else, e.g. missing namespace or extra segments, raises this error.","triggerScenarios":"Passing 'persistent://tenant/topic' (missing namespace) or a name with 5+ segments after the scheme; also empty tenant/namespace strings yielding empty parts.","commonSituations":"Hand-editing topic names, template placeholders left unfilled (e.g. 'persistent://{{tenant}}/{{ns}}/topic' partially substituted), or legacy vs new cluster naming confusion.","solutions":["Format as persistent://<tenant>/<namespace>/<topic> (3 segments after scheme)","For legacy clusters use persistent://<tenant>/<cluster>/<namespace>/<topic>","Ensure no empty segments (double slashes) and no extra segments","Print the topic string before parsing to verify substitution of templated values"],"exampleFix":"// before\npf.ParseTopicName(\"persistent://public/mytopic\") // error\n// after\npf.ParseTopicName(\"persistent://public/default/mytopic\")","handlingStrategy":"validation","validationCode":"rest := topic\nif i := strings.Index(rest, \"://\"); i >= 0 { rest = rest[i+3:] }\nn := len(strings.Split(rest, \"/\"))\nif n != 3 && n != 4 { return fmt.Errorf(\"topic needs 3 or 4 path segments, got %d\", n) }","typeGuard":null,"tryCatchPattern":"tn, err := pf.ParseTopicName(topic)\nif err != nil {\n    return fmt.Errorf(\"invalid topic %q: %w\", topic, err)\n}","preventionTips":["Verify templated topic names fully render before parsing","Use persistent://<tenant>/<namespace>/<topic> consistently","Check for empty segments (double slashes) in configs"],"tags":["go","topic-name","validation","pulsar-functions"],"backgroundTag":"invalid-topic-name","analyzedSha":"820761864ed8e2a7d2e52dd9763ad2ae117c1395","analyzedAt":"2026-09-06T00:14:20.138Z","contentChangedAt":"2026-09-06T00:14:20.138Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}