apache/pulsar · error · IllegalStateException

Synthetic layout missing segment_id= + partition + (N= + n

Error message

Synthetic layout missing segment_id= + partition +  (N= + n + )

What it means

SegmentRouter.routeModN maps a message key hash onto an active segment via a sign-safe modulo of the hash by the number of segments (N). This IllegalStateException is thrown when the computed partition index does not match any currently active segment, meaning the in-memory synthetic layout has drifted from the expected 0..N-1 segment id range. The library throws it rather than silently dropping or misrouting the message.

Source

Thrown at pulsar-client-v5/src/main/java/org/apache/pulsar/client/impl/v5/SegmentRouter.java:103

            }
        }
        return true;
    }

    /**
     * Mod-N routing over {@code segment_id}, matching v4 partitioned-topic routing
     * ({@code signSafeMod(murmurHash3_32(key), N)}).
     */
    private static long routeModN(String key, List<ActiveSegment> activeSegments) {
        int hash32 = Murmur3_32Hash.getInstance().makeHash(key.getBytes(StandardCharsets.UTF_8));
        int n = activeSegments.size();
        int partition = signSafeMod(hash32, n);
        for (var segment : activeSegments) {
            if (segment.segmentId() == partition) {
                return segment.segmentId();
            }
        }
        throw new IllegalStateException(
                "Synthetic layout missing segment_id=" + partition + " (N=" + n + ")");
    }

    private static int signSafeMod(int dividend, int divisor) {
        int mod = dividend % divisor;
        return mod < 0 ? mod + divisor : mod;
    }

    /**
     * The raw 32-bit {@code Murmur3_32} hash of a key. Its two 16-bit halves drive the two independent
     * rings — high half → segment routing ({@link #segmentHash}), low half → entry-bucketing
     * ({@link #entryBucketHash}, PIP-486). Compute this <b>once</b> per key and split it, rather than
     * hashing the key twice.
     *
     * <p>The <i>raw</i> (unmasked) hash is required so the high half is full-range: {@code makeHash}
     * clears bit 31, which would confine the high half to {@code [0, 0x7FFF]}.
     */
    static int murmur(byte[] keyBytes) {

View on GitHub (pinned to 820761864e)

Solutions

  1. Rebuild or refresh the router's activeSegments list so it is contiguous and consistent with the value of n used for the modulo.
  2. Route under the same lock/consistency point that mutates activeSegments so segment removal cannot race with routing.
  3. Verify segment ids cover 0..N-1 at construction; fail fast or recompute n from activeSegments.size() instead of a stale count.
  4. Catch IllegalStateException in route() callers and retry against a refreshed router.

Example fix

// before
int n = configuredSegmentCount;
int partition = signSafeMod(hash32, n);
for (var segment : activeSegments) {
    if (segment.segmentId() == partition) {
        return segment.segmentId();
    }
}
throw new IllegalStateException("Synthetic layout missing segment_id=" + partition + " (N=" + n + ")");
// after
var snapshot = new ArrayList<>(activeSegments); // consistent view, taken under lock
int n = snapshot.size();
int partition = signSafeMod(hash32, n);
return snapshot.stream()
    .filter(s -> s.segmentId() == partition)
    .findFirst()
    .map(Segment::segmentId)
    .orElseGet(() -> snapshot.get(Math.floorMod(partition, snapshot.size())).segmentId());
Defensive patterns

Strategy: validation

Validate before calling

if (activeSegments.size() != n || activeSegments.stream().mapToInt(Segment::segmentId).distinct().count() != n) {
    throw new IllegalStateException("segment layout not contiguous for N=" + n);
}

Try / catch

try { return router.route(key); } catch (IllegalStateException e) { router.refreshLayout(); return router.route(key); }

Prevention

When it happens

Trigger: Calling route() (which delegates to routeModN) when activeSegments does not contain a segment whose segmentId() equals signSafeMod(hash32, n) — e.g. segments were closed/removed, reordered, or the active segment list is sparse while n still counts all segments.

Common situations: A segment was closed or failed while routing continued with a stale count of active segments; concurrent layout changes (segment add/remove) racing with route; constructing the router with non-contiguous segment ids; rebalancing/reshuffling the synthetic layout mid-flight.

Related errors


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