risingwavelabs/risingwave · error
topic name cannot be empty
Error message
topic name cannot be empty
What it means
The final component of a Pulsar topic (the topic name itself) must be non-empty. parse_topic constructs the Topic struct and then rejects it if the topic field is an empty string, since an empty leaf name is not addressable on the broker.
Solutions
- Remove the trailing slash and supply a real topic name
- Use 'persistent://public/default/mytopic' style input
- Trim the topic string before passing it to the connector
Example fix
// before
let topic = parse_topic("persistent://public/default/");
// after
let topic = parse_topic("persistent://public/default/mytopic"); Defensive patterns
Strategy: validation
Validate before calling
function validateNonEmptyLeaf(topic) {
const leaf = (topic.split('://')[1] ?? topic).split('/').pop();
if (!leaf) throw new Error(`topic name cannot be empty: ${topic}`);
} Type guard
const hasNonEmptyLeaf = (t) => Boolean((t.split('://')[1] ?? t).split('/').pop()); Try / catch
try { parse_topic(input); } catch (e) { if (String(e).includes('topic name cannot be empty')) { stripTrailingSlashAndRetry(input); } else { throw e; } } Prevention
- Trim trailing slashes from copied broker console URLs
- Never build topic strings from unvalidated template placeholders
- Trim whitespace before passing topic strings to the connector
When it happens
Trigger: Calling parse_topic with a URL ending in '/', e.g. 'persistent://public/default/' or 'persistent://public/default//', producing parts[2] == "".
Common situations: Trailing slash left over from copy-pasting a broker console URL, or programmatically building topic strings with template placeholders left blank.
Understand the failure class
Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.
Related errors
- credentials file does not exist
- credentials_url must be a valid URL (s3://, file://) or an…
- invalid topic name ' '; it must be in the format / /
- missing FORMAT ... ENCODE ...
- PulsarIcebergReader has already been deprecated
AI-assisted analysis of risingwavelabs/risingwave@6469eb736d (2026-09-11).
Data as JSON: /api/errors/5bbdada96a7e7675.
Report an issue: GitHub.
Appendix: source
Thrown at src/connector/src/source/pulsar/topic.rs:168
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)
}
pub(crate) async fn check_topic_exists(
client: &Pulsar<TokioExecutor>,
topic: &Topic,
) -> Result<()> {
// issue about api `get_topics_of_namespace`:
// for partitioned topic, the api will return all sub-topic of the topic instead of the topic itself
// Reduce async state machine size (see `clippy::large_futures`).
let topics_on_broker = Box::pin(client.get_topics_of_namespace(
format!("{}/{}", topic.tenant, topic.namespace),
LookupMode::All,
))
.await?;
if !topics_on_broker.contains(&topic.to_string()) {View on GitHub (pinned to 6469eb736d)