risingwavelabs/risingwave · error
invalid topic name ' '; it must be in the format / /
Error message
invalid topic name '{}'; it must be in the format <tenant>/<namespace>/<topic> What it means
After stripping the domain, a Pulsar topic must have exactly three slash-separated components: tenant, namespace, and topic name. parse_topic splits the remainder with splitn(3,'/') and bails when the count is not 3, since it cannot build a valid Topic struct otherwise.
Solutions
- Provide the topic as '<tenant>/<namespace>/<topic>', e.g. 'public/default/events'
- Verify the full string after '://' contains exactly two '/' separators
- Remove any extra path segments or append the missing namespace/tenant
Example fix
// before
let topic = parse_topic("persistent://public/events");
// after
let topic = parse_topic("persistent://public/default/events"); Defensive patterns
Strategy: validation
Validate before calling
function validatePulsarTopicPath(topic) {
const rest = topic.split('://')[1] ?? topic;
if (rest.split('/').length !== 3) {
throw new Error(`topic must be <tenant>/<namespace>/<topic>: ${rest}`);
}
} Type guard
const isThreePartTopic = (t) => (t.split('://')[1] ?? t).split('/').length === 3; Try / catch
try { parse_topic(input); } catch (e) { if (String(e).includes('invalid topic name')) { normalizeToTenantNsTopic(input); } else { throw e; } } Prevention
- Copy full topic URLs (persistent://tenant/ns/topic) rather than truncating
- Strip partition suffixes like '-partition-0' before validating if using the non-partitioned name
- Add config-time linting that checks the slash count of topic strings
When it happens
Trigger: Calling parse_topic with a rest path like 'tenant/topic' (missing namespace), 'tenant/namespace/topic/partition-extra', or a domain-only URL such as 'persistent://' with no path.
Common situations: Users providing only 'my-topic' with embedded slashes that do not resolve to 3 parts, truncating a copied topic URL, or accidentally appending a partition suffix that changes the part count.
Understand the failure class
Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.
Related errors
- credentials file does not exist
- credentials_url must be a valid URL (s3://, file://) or an…
- illegal message id string
- missing FORMAT ... ENCODE ...
- missing FORMAT ... ENCODE ...
AI-assisted analysis of risingwavelabs/risingwave@6469eb736d (2026-09-11).
Data as JSON: /api/errors/cbd24344b9cfe285.
Report an issue: GitHub.
Appendix: source
Thrown at src/connector/src/source/pulsar/topic.rs:153
}
let parts: Vec<&str> = complete_topic.splitn(2, "://").collect();
let domain = match parts[0] {
PERSISTENT_DOMAIN | NON_PERSISTENT_DOMAIN => parts[0],
_ => {
bail!(
"The domain only can be specified as 'persistent' or 'non-persistent'. Input domain is '{}'",
parts[0]
);
}
};
let rest = parts[1];
let parts: Vec<&str> = rest.splitn(3, '/').collect();
if parts.len() != 3 {
bail!(
"invalid topic name '{}'; it must be in the format <tenant>/<namespace>/<topic>",
rest
);
}
let parsed_topic = Topic {
domain: domain.to_owned(),
tenant: parts[0].to_owned(),
namespace: parts[1].to_owned(),
topic: parts[2].to_owned(),
partition_index: get_partition_index(complete_topic.as_str())?,
};
if parsed_topic.topic.is_empty() {
bail!("topic name cannot be empty".to_owned());
}
Ok(parsed_topic)View on GitHub (pinned to 6469eb736d)