{"record":{"id":"1c224adf49cc0e95","repo":"apache/skywalking","slug":"registry-misconfigured","errorCode":"registry_misconfigured","errorMessage":"No DebugRecorderFactory registered for catalog {catalog} — phase 1d wiring incomplete.","messagePattern":"No DebugRecorderFactory registered for catalog (.+?) — phase 1d wiring incomplete\\.","errorType":"http","errorClass":"IllegalStateException","httpStatus":500,"severity":"critical","filePath":"oap-server/server-admin/dsl-debugging/src/main/java/org/apache/skywalking/oap/server/admin/dsl/debugging/session/DebugSessionRegistry.java","lineNumber":186,"sourceCode":"                                        final String clientId, final SessionLimits limits) {\n        final DebugSession existing = sessions.get(sessionId);\n        if (existing != null) {\n            return new InstallOutcome(InstallOutcome.Status.ALREADY_INSTALLED, existing);\n        }\n        // Resolve the holder FIRST. The active-session ceiling only applies to nodes\n        // that actually own the rule — if this node doesn't have the live artifact,\n        // surfacing TOO_MANY_SESSIONS would falsely reject a session whose actual\n        // holder lives on a peer with capacity, breaking the LB-safe contract. The\n        // load-shedding role of the cap is preserved: an attacker spamming installs\n        // at unloaded rules still gets NOT_LOCAL (the cheap path), and only nodes\n        // that would actually bind a recorder enforce the cap.\n        final GateHolder holder = resolveHolder(ruleKey);\n        if (holder == null) {\n            return InstallOutcome.NOT_LOCAL_OUTCOME;\n        }\n        final DebugRecorderFactory factory = resolveFactory(ruleKey);\n        if (factory == null) {\n            throw new IllegalStateException(\n                \"No DebugRecorderFactory registered for catalog \" + ruleKey.getCatalog()\n                    + \" — phase 1d wiring incomplete.\");\n        }\n        final AbstractDebugRecorder recorder = factory.create(sessionId, ruleKey, holder, limits);\n        final long now = System.currentTimeMillis();\n        final DebugSession session = new DebugSession(\n            sessionId, clientId, ruleKey, recorder, holder, now,\n            now + limits.getRetentionMillis()\n        );\n        // Atomic slot reservation + holder bind: cap-check, putIfAbsent, AND\n        // holder.addRecorder all run under the same lock so a concurrent\n        // {@link #uninstall} (or reaper-driven stop) cannot remove the session\n        // BETWEEN registry-publication and holder-binding and leave an\n        // unreachable recorder bound to the holder. Both install and uninstall\n        // take the registry lock first, then the holder lock (via add/remove\n        // recorder which is synchronized on the holder), preserving the same\n        // lock order in both directions — no deadlock.\n        final DebugSession reserved;","sourceCodeStart":168,"sourceCodeEnd":204,"githubUrl":"https://github.com/apache/skywalking/blob/102af09b4a56064e22050dded10e2c52e490d040/oap-server/server-admin/dsl-debugging/src/main/java/org/apache/skywalking/oap/server/admin/dsl/debugging/session/DebugSessionRegistry.java#L168-L204","documentation":"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.","triggerScenarios":"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.","commonSituations":"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","solutions":["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()","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","If this is a custom build, add/restore the registerRecorderFactory(...) call in the owning module's provider start phase and restart the OAP node","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"],"exampleFix":"// before (custom provider, recorder never registered)\npublic void start() {\n    // ... engine wiring ...\n}\n// after\npublic void start() {\n    // ... engine wiring ...\n    debugSessionRegistry.registerRecorderFactory(new LalDebugRecorderFactory(...));\n}","handlingStrategy":"validation","validationCode":"final DebugRecorderFactory factory = registry.resolveFactoryFor(ruleKey); // expose or reflect resolveFactory\nif (factory == null) {\n    return error(\"debug-recorder-factory-missing for catalog \" + ruleKey.getCatalog()\n        + \" — check module wiring before installing sessions\");\n}","typeGuard":null,"tryCatchPattern":"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.","preventionTips":["Boot-time smoke test: after OAP start, verify every loaded catalog has a matching DebugRecorderFactory before opening the debug-session API","Keep dsl-debugging and the engine modules in one feature set — never enable one without the other in packaging configs","Add a startup assertion that iterates loaded catalogs and fails module start if resolveFactory returns null"],"tags":["configuration","dsl-debugging","module-wiring","registry"],"backgroundTag":null,"analyzedSha":"102af09b4a56064e22050dded10e2c52e490d040","analyzedAt":"2026-08-14T10:47:52.647Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}