apache/skywalking · critical · IllegalStateException

registry_misconfigured

registry_misconfigured

Error message

No DebugRecorderFactory registered for catalog {catalog} — phase 1d wiring incomplete.

What it means

Thrown by DebugSessionRegistry.install when a rule's GateHolder resolves on this node but no registered DebugRecorderFactory claims the rule's catalog. Factories are added via registerRecorderFactory() and resolved by iterating a CopyOnWriteArrayList asking each factory to match the RuleKey; an empty or incomplete list means the dsl-debugging module was wired without an engine (LAL/MAL/OAL) recorder provider — the message calls this 'phase 1d wiring incomplete'. This is a module-configuration defect, not a user-input error: it can only happen when the catalog's engine module never registered its factory at boot.

Source

Thrown at oap-server/server-admin/dsl-debugging/src/main/java/org/apache/skywalking/oap/server/admin/dsl/debugging/session/DebugSessionRegistry.java:186

                                        final String clientId, final SessionLimits limits) {
        final DebugSession existing = sessions.get(sessionId);
        if (existing != null) {
            return new InstallOutcome(InstallOutcome.Status.ALREADY_INSTALLED, existing);
        }
        // Resolve the holder FIRST. The active-session ceiling only applies to nodes
        // that actually own the rule — if this node doesn't have the live artifact,
        // surfacing TOO_MANY_SESSIONS would falsely reject a session whose actual
        // holder lives on a peer with capacity, breaking the LB-safe contract. The
        // load-shedding role of the cap is preserved: an attacker spamming installs
        // at unloaded rules still gets NOT_LOCAL (the cheap path), and only nodes
        // that would actually bind a recorder enforce the cap.
        final GateHolder holder = resolveHolder(ruleKey);
        if (holder == null) {
            return InstallOutcome.NOT_LOCAL_OUTCOME;
        }
        final DebugRecorderFactory factory = resolveFactory(ruleKey);
        if (factory == null) {
            throw new IllegalStateException(
                "No DebugRecorderFactory registered for catalog " + ruleKey.getCatalog()
                    + " — phase 1d wiring incomplete.");
        }
        final AbstractDebugRecorder recorder = factory.create(sessionId, ruleKey, holder, limits);
        final long now = System.currentTimeMillis();
        final DebugSession session = new DebugSession(
            sessionId, clientId, ruleKey, recorder, holder, now,
            now + limits.getRetentionMillis()
        );
        // Atomic slot reservation + holder bind: cap-check, putIfAbsent, AND
        // holder.addRecorder all run under the same lock so a concurrent
        // {@link #uninstall} (or reaper-driven stop) cannot remove the session
        // BETWEEN registry-publication and holder-binding and leave an
        // unreachable recorder bound to the holder. Both install and uninstall
        // take the registry lock first, then the holder lock (via add/remove
        // recorder which is synchronized on the holder), preserving the same
        // lock order in both directions — no deadlock.
        final DebugSession reserved;

View on GitHub (pinned to 102af09b4a)

Solutions

  1. Check the module/provider list in application.yml: ensure the module that owns the failing catalog (per the error's catalog name) is enabled, so its provider registers a DebugRecorderFactory at start()
  2. Verify the factory's supported-catalog/satisfiedBy logic actually returns true for the catalog named in the message — a typo in the catalog string silently never matches
  3. If this is a custom build, add/restore the registerRecorderFactory(...) call in the owning module's provider start phase and restart the OAP node
  4. As a workaround only, route debug installs to a node where the factory is registered — but treat the underlying wiring gap as a defect to fix

Example fix

// before (custom provider, recorder never registered)
public void start() {
    // ... engine wiring ...
}
// after
public void start() {
    // ... engine wiring ...
    debugSessionRegistry.registerRecorderFactory(new LalDebugRecorderFactory(...));
}
Defensive patterns

Strategy: validation

Validate before calling

final DebugRecorderFactory factory = registry.resolveFactoryFor(ruleKey); // expose or reflect resolveFactory
if (factory == null) {
    return error("debug-recorder-factory-missing for catalog " + ruleKey.getCatalog()
        + " — check module wiring before installing sessions");
}

Try / catch

catch (IllegalStateException e) when message starts with 'No DebugRecorderFactory registered': treat as permanent config error — fail fast, alert the operator, do NOT retry; check module wiring before the next install attempt.

Prevention

When it happens

Trigger: Calling the debug-session install API (gRPC/REST path into DebugSessionRegistry.install) for a rule in catalog X, on a node where resolveHolder(ruleKey) returns a holder but resolveFactory(ruleKey) returns null — i.e. the rule loaded (holder exists) yet no DebugRecorderFactory.satisfiedBy match exists for that catalog. Typical when a custom OAP packaging starts the dsl-debugging module without the module that registers recorders for that catalog, or when a new catalog was added without a corresponding factory registration.

Common situations: Custom OAP distribution that includes dsl-debugging but drops the module whose provider calls registerRecorderFactory() for the affected catalog; Upgrading to a version where a new rule catalog exists but the recorder factory SPI implementation was not added/registered; Test harnesses that construct DebugSessionRegistry directly and forget to call registerRecorderFactory before install

Related errors


AI-assisted analysis of apache/skywalking@102af09b4a (2026-08-14). Data as JSON: /api/errors/1c224adf49cc0e95. Report an issue: GitHub.