Skip to content

OpenTelemetry sub-workflow executions not traced (missing ModulesHooksRegistry.addHooks in getLifecycleHooksForSubExecutions) #28592

@BCSHroyer

Description

@BCSHroyer

Bug Description

OpenTelemetry tracing does not trace sub-workflows invoked via the Execute Workflow node. When a parent workflow calls a sub-workflow, the parent trace shows a single node.execute span for the Execute Workflow node, but none of the sub-workflow's workflow.execute or node.execute spans are emitted. This makes it impossible to see the full execution graph of any workflow that uses sub-workflows.

Root cause: In packages/cli/src/execution-lifecycle/execution-lifecycle-hooks.ts, the factory getLifecycleHooksForSubExecutions is the only lifecycle-hooks factory that does not call Container.get(ModulesHooksRegistry).addHooks(hooks). The other three (getLifecycleHooksForRegularMain, getLifecycleHooksForScalingMain, getLifecycleHooksForScalingWorker) all register module hooks. Because sub-executions bypass the registry, the OTEL module's @OnLifecycleEvent handlers never fire for them. This affects any backend module that participates in the lifecycle, not just OTEL.

Secondary gap: WorkflowExecuteBeforeContext does not carry parentExecution, so even if module hooks were registered, there is no way to link the sub-workflow's workflow.execute span to the parent's Execute Workflow node.execute span to produce a single nested trace.

Verified on the n8n@2.17.2 tag and still present on master. No existing issue or PR addresses this.

cc @geemanjs @alielkhateeb, who authored the OTEL module in #27528 and #27789.

To Reproduce

  1. Enable native OTEL on an n8n instance:
    • N8N_OTEL_ENABLED=true
    • N8N_OTEL_EXPORTER_OTLP_ENDPOINT=http://<collector>:4318
    • Point at any OTLP-compatible backend (Grafana Tempo, Jaeger, Alloy, etc.).
  2. Create a workflow called "Child" with one or more nodes (e.g. Set → Code).
  3. Create a workflow called "Parent" with a trigger, a Set node, and an Execute Workflow node that calls "Child".
  4. Execute Parent.
  5. Inspect traces in the OTLP backend.

Expected behavior

One trace with a clean parent/child hierarchy, for example:

workflow.execute  (Parent)
├── node.execute  Trigger
├── node.execute  Set
└── node.execute  Execute Workflow
    └── workflow.execute  (Child)
        ├── node.execute  Set
        └── node.execute  Code

All spans share a single traceId. The Child's workflow.execute span's parentSpanId equals the Parent's Execute Workflow node.execute span id.

Actual: Only the Parent's workflow.execute and its node.execute spans are emitted. The Child workflow's spans never appear. Nothing links the parent execution to the child execution in the tracing backend.

Debug Info

Operating System

Windows Server 2022

n8n Version

2.17.2

Node.js Version

22.22.2

Database

PostgreSQL

Execution mode

queue

Hosting

self hosted

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions