Skip to content

Node.js OpenTelemetry troubleshooting

Most Node.js instrumentation problems come from how and when the SDK is loaded. Work through the Node-specific checks below, then the shared checks at the bottom.

The auto-instrumentations patch libraries as they are loaded, so the SDK must start before your application imports anything. How you achieve that depends on your module system.

CommonJS (the default; require throughout your code): load the SDK with --require, which runs before your entry file.

Terminal window
node --require ./instrumentation.js server.js

ES modules ("type": "module" in package.json, or .mjs files): --require cannot patch modules loaded with import. Start the SDK with --import and register the OpenTelemetry loader hook so imported libraries are patched:

Terminal window
node \
--experimental-loader=@opentelemetry/instrumentation/hook.mjs \
--import ./instrumentation.mjs \
server.js

Convert the initialization module to ESM syntax:

instrumentation.mjs
import { NodeSDK } from '@opentelemetry/sdk-node';
import { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node';
import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-proto';
import { OTLPMetricExporter } from '@opentelemetry/exporter-metrics-otlp-proto';
import { OTLPLogExporter } from '@opentelemetry/exporter-logs-otlp-proto';
import { PeriodicExportingMetricReader } from '@opentelemetry/sdk-metrics';
import { BatchLogRecordProcessor } from '@opentelemetry/sdk-logs';
const sdk = new NodeSDK({
traceExporter: new OTLPTraceExporter(),
metricReader: new PeriodicExportingMetricReader({
exporter: new OTLPMetricExporter(),
}),
logRecordProcessors: [new BatchLogRecordProcessor(new OTLPLogExporter())],
instrumentations: [getNodeAutoInstrumentations()],
});
sdk.start();
process.on('SIGTERM', () => {
sdk.shutdown().finally(() => process.exit(0));
});

If the service reports metrics but no traces, or traces are missing spans you expect:

  • Load order. The most common cause. The SDK must start before the framework is imported. Confirm --require/--import points at your instrumentation file, or that its import is the first line of your entry file. A framework imported before the SDK starts is never patched.
  • Manual spans not ended. A span is only exported after span.end() runs. Ensure end() is called in a finally block so it runs even when the operation throws.
  • Unsupported library or version. The auto-instrumentations cover specific libraries and version ranges. A library outside those ranges emits no spans; add manual spans around it.
  • Wrong runtime (Next.js). Routes running on the Edge runtime are not instrumented by a NodeSDK. Confirm the route runs on the Node.js runtime and that you instrument through @vercel/otel.
  • Sampling. If you set OTEL_TRACES_SAMPLER to a ratio-based sampler, low-frequency requests may be dropped. Remove the override to confirm the sampler is the cause.

If the SDK starts but no data reaches Osuite, the exporter is failing to send. Enable diagnostic logging to see export attempts — add this to the top of the initialization module:

const { diag, DiagConsoleLogger, DiagLogLevel } = require('@opentelemetry/api');
diag.setLogger(new DiagConsoleLogger(), DiagLogLevel.DEBUG);

Then check for these causes in the log output:

  • Endpoint format. OTEL_EXPORTER_OTLP_ENDPOINT must include the https:// scheme and port 443, for example https://ingest.<region>.osuite.io:443. The HTTP/protobuf exporter appends the signal path (/v1/traces, /v1/metrics, /v1/logs) itself — do not add it.
  • Header format. OTEL_EXPORTER_OTLP_HEADERS must be x-osuite-ingest-token=<your-ingest-token>. Multiple headers are comma-separated key=value pairs.
  • Authentication (404). The ingest token is missing, mistyped, or rotated. Ingest matches the token at the edge, so an unrecognised token returns 404 rather than 401/403. Issue a fresh token in Settings → API Keys.
  • DNS or network (ENOTFOUND, ECONNREFUSED). The host cannot reach the ingest endpoint. Confirm outbound access to port 443 and that the region hostname is correct.
  • TLS errors. A corporate proxy or custom certificate authority is intercepting the connection. Configure the proxy or trust store so the host can complete the TLS handshake to the ingest endpoint.

No data in Osuite after a few minutes? Work through these checks.

  • Endpoint — confirm the exporter targets exactly ingest.<region>.osuite.io:443 for your region, over TLS.
  • Token — confirm the ingest header carries a valid <your-ingest-token> and has not been rotated.
  • Pipeline — confirm the signal you expect (traces, logs, or metrics) is wired into an active pipeline with the otlp/osuite exporter attached.
  • Export errors — check the application or Collector logs for OTLP export failures (auth, DNS, TLS, connection refused).
  • Network — confirm the host has outbound access to the ingest endpoint on port 443.
  • Timing — allow up to a minute for the first data to appear before assuming a failure.

Still stuck? Ask the Investigation Agent or contact support.