Skip to content

Plugin's onDiagnosticEvent() and gateway's emitDiagnosticEvent() use different module instances due to jiti isolation. Events never reach the plugin. Needs core fix (globalThis or context injection). #5190

@jmeadlock

Description

@jmeadlock

Bug: diagnostics-otel plugin doesn't receive events due to module isolation

Summary

The diagnostics-otel plugin loads successfully and subscribes to diagnostic events via onDiagnosticEvent(), but never receives any events because the plugin's module instance is isolated from the gateway's module instance.

Environment

  • Clawdbot version: 2026.1.24-3
  • Node.js: v25.4.0
  • OS: macOS (Darwin arm64)

Steps to Reproduce

  1. Enable diagnostics in config:
{
  "diagnostics": {
    "enabled": true,
    "otel": {
      "enabled": true,
      "endpoint": "http://localhost:4318",
      "protocol": "http/protobuf",
      "serviceName": "milo",
      "traces": true,
      "metrics": true
    }
  }
}
  1. Add diagnostics-otel to plugins allow list and entries
  2. Start OTel collector on localhost:4318
  3. Restart gateway
  4. Observe that no metrics are ever sent to collector

Debug Findings

Added debug logging to dist/infra/diagnostic-events.js:

export function onDiagnosticEvent(listener) {
    console.error('[DEBUG] Adding listener. Current count:', listeners.size);
    listeners.add(listener);
    console.error('[DEBUG] After add:', listeners.size);
    // ...
}

export function emitDiagnosticEvent(event) {
    console.error('[DEBUG] Emitting, listeners:', listeners.size);
    // ...
}

Results:

  • When plugin calls onDiagnosticEvent(): listener count goes 0 → 1 ✓
  • When gateway calls emitDiagnosticEvent(): listener count is 0 ✗

This proves the plugin and gateway are using different module instances of diagnostic-events.js.

Root Cause

The plugin is loaded via jiti (TypeScript loader), which appears to create a separate module cache. When the plugin imports onDiagnosticEvent from clawdbot/plugin-sdk, it gets a different instance of the listeners Set than the one used by the gateway's emitDiagnosticEvent.

Expected Behavior

The plugin should receive diagnostic events and export them to the OTel collector.

Actual Behavior

Plugin loads, SDK starts, subscribes to events, but never receives any because module isolation breaks the shared event emitter.

Possible Fixes

  1. Use a global registry (e.g., globalThis.__clawdbot_diagnostic_listeners__) instead of module-level variable
  2. Pass the event emitter through the plugin context
  3. Ensure jiti shares the module cache with the main process

Workaround

None known - core code change required.

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions