apache/pulsar · error · IllegalArgumentException

Invalid managedLedger name: ${mlName}

Error message

Invalid managedLedger name: ${mlName}

What it means

fromPersistenceNamingEncoding converts a legacy managed-ledger storage path (the on-disk name used by BookKeeper/Pulsar metadata, with encoded segments) back into a topic URL. If the managedLedger name does not have the expected segment structure (it is not a recognized legacy or current encoding), the method throws this IllegalArgumentException because the name cannot be decoded.

Source

Thrown at pulsar-common/src/main/java/org/apache/pulsar/common/naming/TopicName.java:490

            return String.format("%s://%s/%s/%s", domain, tenant, namespacePortion, localName);
        } else if (parts.size() == 5) {
            if ("segment".equals(parts.get(2))) {
                // Segment topic ML name: tenant/namespace/segment/topic/descriptor
                tenant = parts.get(0);
                namespacePortion = parts.get(1);
                localName = Codec.decode(parts.get(3));
                return String.format("segment://%s/%s/%s/%s", tenant, namespacePortion, localName, parts.get(4));
            }
            // Legacy V1 managed ledger name: tenant/cluster/namespace/domain/topic
            // Convert to V2 format, dropping the cluster component
            tenant = parts.get(0);
            // parts.get(1) is the cluster, which we drop
            namespacePortion = parts.get(2);
            domain = parts.get(3);
            localName = Codec.decode(parts.get(4));
            return String.format("%s://%s/%s/%s", domain, tenant, namespacePortion, localName);
        } else {
            throw new IllegalArgumentException("Invalid managedLedger name: " + mlName);
        }
    }

    /**
     * Get a string suitable for completeTopicName lookup.
     *
     * <p>Example:
     *
     * <p>persistent://tenant/namespace/completeTopicName ->
     *   persistent/tenant/namespace/completeTopicName
     *
     * @return
     */
    public String getLookupName() {
        return String.format("%s/%s/%s/%s", domain, tenant, namespacePortion, getEncodedLocalName());
    }

    public String getSchemaName() {

View on GitHub (pinned to 820761864e)

Solutions

  1. Pass the full managed-ledger name exactly as stored (all segments), e.g. 'tenant/cluster/namespace/domain/persistent/localName' legacy form or the current 'tenant/namespace/persistent/localName'
  2. Verify you are not truncating the path when extracting from metadata storage
  3. If converting a topic name to ledger form, use TopicName.getPersistenceNamingEncoding() first and round-trip it

Example fix

// before
TopicName.fromPersistenceNamingEncoding("persistent/my-topic");
// after
TopicName.fromPersistenceNamingEncoding("my-tenant/my-cluster/my-ns/persistent/my-topic");
Defensive patterns

Strategy: validation

Validate before calling

public static boolean looksLikeManagedLedgerName(String mlName) {
    if (mlName == null) return false;
    String[] parts = mlName.split("/");
    return parts.length == 5 // legacy: tenant/cluster/namespace/domain/localName
        || (parts.length == 4 && (parts[2].equals("persistent") || parts[2].equals("non-persistent")));
}

Type guard

public static boolean isDecodableLedgerName(String s) { return s != null && s.split("/").length >= 4; }

Try / catch

try {
    String topicUrl = TopicName.fromPersistenceNamingEncoding(mlName);
} catch (IllegalArgumentException e) {
    log.error("Cannot decode managed ledger name '{}': {}", mlName, e.getMessage());
}

Prevention

When it happens

Trigger: Calling TopicName.fromPersistenceNamingEncoding(mlName) with a string that does not match the expected managed-ledger naming scheme — wrong number of slash-separated parts (the code expects 5 parts for the legacy format, or the modern 3-part tenant/namespace/local form), or a corrupted/shortened path read from metadata storage.

Common situations: Reading entries directly from ZooKeeper/BookKeeper metadata and passing the raw ledger path; hand-building ledger names; migrating data between Pulsar versions where the naming scheme differs; passing an encoded name with missing segments.

Related errors


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