JavaScript Source Maps
Uptrace can resolve minified JavaScript stack traces back to original source code using source maps. When a browser error is captured via the OpenTelemetry Browser SDK, Uptrace parses the exception.stacktrace attribute, applies source maps, and replaces minified file/line/column references with the original source locations.
How it works
- Your browser app sends an error span with
telemetry.sdk.language = webjs. - Uptrace extracts the
exception.stacktraceattribute and parses it (Chrome and Firefox formats). - For each stack frame, Uptrace resolves the original source location using a source map.
- The stack trace is updated with original file names, line numbers, column numbers, and function names.
Source maps are resolved in this order:
- Uploaded source maps — checked first. Matched by project, minified URL, service name, and service version.
- HTTP fetch — if no uploaded map matches, Uptrace fetches the minified JS file, looks for a
//# sourceMappingURL=comment orSourceMapHTTP header, then fetches and parses the referenced source map.
Resolved positions are cached for 6 hours. Failed lookups are cached for 1 hour to avoid repeated requests.
Configuration
Source map processing is enabled by default. For self-hosted Uptrace, see the configuration reference for all available options including cache tuning and enabling the upload API.
In air-gapped environments where Uptrace cannot reach external URLs, set disabled: true and use the upload API instead (upload_enabled: true).
Uploading source maps
When upload_enabled: true in the configuration, you can upload source maps via the REST API. This is the recommended approach for production deployments because it does not require Uptrace to have internet access and gives you full control over which maps are available.
Upload a source map
curl -X POST "https://<uptrace-host>/api/v1/sourcemaps" \
-H "uptrace-dsn: https://<token>@<uptrace-host>/<project_id>" \
-F "file=@dist/app.js.map" \
-F "minified_url=https://example.com/static/app.js" \
-F "service_name=frontend" \
-F "service_version=1.2.3"
The upload endpoint authenticates with a project token (DSN) — the same DSN used to send telemetry data. You can find it in your project settings.
| Field | Required | Description |
|---|---|---|
file | yes | The source map JSON file. |
minified_url | yes | The URL of the minified JavaScript file as seen in errors. |
service_name | no | Service name to scope the map (matches service.name). |
service_version | no | Service version to scope the map (matches service.version). |
If a source map with the same (project_id, minified_url, service_name, service_version) already exists, it is replaced.
List source maps
curl "https://<uptrace-host>/api/v1/sourcemaps/<project_id>" \
-H "Authorization: Bearer <user_token>"
Returns all uploaded source maps for the project (without the map data itself). This endpoint requires a user token with edit permissions.
Delete a source map
curl -X DELETE "https://<uptrace-host>/api/v1/sourcemaps/<project_id>/<sourcemap_id>" \
-H "Authorization: Bearer <user_token>"
Requires a user token with edit permissions.
Limits
- Maximum 200 source maps per project.
- Maximum 64 MB per upload.
- The source map must be valid JSON in source map v3 format.
Integrating with your build
Upload source maps as part of your CI/CD pipeline after every build. Here is an example using a shell script:
#!/bin/bash
set -euo pipefail
UPTRACE_DSN="https://<token>@api.uptrace.dev/<project_id>"
SERVICE_NAME="frontend"
SERVICE_VERSION=$(git rev-parse --short HEAD)
DIST_DIR="dist/assets"
for map in "$DIST_DIR"/*.js.map; do
js_file="${map%.map}"
js_name=$(basename "$js_file")
minified_url="https://example.com/assets/$js_name"
echo "Uploading $map -> $minified_url"
curl -s -X POST "https://api.uptrace.dev/api/v1/sourcemaps" \
-H "uptrace-dsn: $UPTRACE_DSN" \
-F "file=@$map" \
-F "minified_url=$minified_url" \
-F "service_name=$SERVICE_NAME" \
-F "service_version=$SERVICE_VERSION"
done
Use service_version to keep source maps for different releases separate. When a new version is deployed, upload its maps with the matching version string. Old maps remain available for errors from previous versions.
Automatic HTTP fetching
When no uploaded source map matches, Uptrace attempts to fetch it over HTTP:
- Fetches the minified JS file URL from the stack frame.
- Looks for
//# sourceMappingURL=<url>at the end of the file, or aSourceMapHTTP response header. - Fetches the referenced source map (supports absolute URLs, relative URLs, and
data:application/json;base64,...inline maps). - Parses and caches the result.
Security: Uptrace blocks requests to private/localhost IP addresses to prevent SSRF. The maximum source map size for HTTP fetching is 48 MB.
This mode requires no setup — if your minified files are publicly accessible and include a sourceMappingURL reference, source maps work automatically.
Stack trace formats
Uptrace parses both Chrome and Firefox stack trace formats:
Chrome:
TypeError: Cannot read property 'foo' of undefined
at bar (https://example.com/static/app.js:1:2345)
at baz (https://example.com/static/app.js:1:6789)
Firefox:
bar@https://example.com/static/app.js:1:2345
baz@https://example.com/static/app.js:1:6789
After source map resolution, the stack trace is rewritten with original file names, line numbers, and function names.
Troubleshooting
Stack traces are not resolved:
- Verify that
sourcemaps.disabledis nottruein your configuration. - Check that spans have
telemetry.sdk.language = webjs. This is set automatically by the OpenTelemetry Browser SDK. - Ensure the
exception.stacktraceattribute is present on error spans.
Uploaded maps are not applied:
- The
minified_urlmust exactly match the URL in the stack trace. - If using
service_nameorservice_version, these must match theservice.nameandservice.versionresource attributes on the span. - Verify the upload succeeded by listing source maps for the project.
HTTP fetch is not working:
- Uptrace must be able to reach the minified file URL from the server.
- The minified file must contain
//# sourceMappingURL=or serve aSourceMapheader. - Private/localhost URLs are blocked for security.
- Check Uptrace logs for fetch errors.