Skip to main content

Source Maps

A JavaScript error from a minified bundle reports a stack like a.min.js:1:24816, which tells you nothing. Upload the build's source maps and StorePilot resolves those frames back to your own files and line numbers when you open the issue.

The map is used on the server and never sent back out. There is no route that returns it, signed or otherwise — the keys to your codebase go in and do not come out. What the dashboard shows is the resolved positions: file, line, column and function name. Your source code is not stored in the error and is not rendered on the page.

What you need first

A release string, set on the site and reported with every error. Symbolication matches on it, so a map uploaded for v1.4.2 is only ever used for errors that say they came from v1.4.2. There is no default and nothing is guessed — see Errors → Releases.

Uploading

One POST per bundle, per release, from your build pipeline. It is authenticated with your site's secret API key — the same header the WordPress proxy uses — because the caller is a build server, never a browser. Keep it out of anything that ships to the client.

curl -X POST https://api.store-pilot.net/ingest/sourcemaps \
-H "X-StorePilot-Key: $STOREPILOT_API_KEY" \
-H "Content-Type: application/json" \
-d "$(jq -n \
--arg release "$RELEASE" \
--arg bundle "app.min.js" \
--rawfile map "dist/app.min.js.map" \
'{release: $release, bundleName: $bundle, map: $map}')"
FieldMeaning
releaseThe build string, 1–60 chars of letters, digits and . _ - +. Must equal what your site reports
bundleNameThe minified file the map belongs to. A bare name, a path or a full URL all work
mapThe .map file's contents, as a JSON string

A successful upload answers {"ok": true, "release": …, "bundleName": …, "bytes": …}. Uploading the same release and bundle again replaces the stored map, so re-running a build is safe.

The body must be a genuine v3 source map — it is parsed and checked before it is stored, and a truncated or wrong-shaped file is rejected with a message saying so rather than silently accepted and useless later. Maps up to 10 MB are accepted. The route allows 60 uploads a minute, which is far above any real release cadence and deliberately generous enough that a pipeline retrying a failed upload is not throttled into shipping a release with no maps.

Matching, and why the URL does not have to line up

Both sides are reduced to a basename before they are compared. A stack frame from https://cdn.example.com/assets/app.min.js?ver=8f21c and a bundleName of dist/app.min.js both reduce to app.min.js and match.

This is deliberate: a CDN path, a cache-busting query string or a hashed directory would otherwise defeat the match, and none of them change which file the frame is in. It also means nothing is ever fetched from a URL in an error report — the lookup is entirely local.

Server-side stacks

A Node SDK report carries a stack of file PATHS rather than URLs — at createOrder (/srv/app/dist/orders.js:41:11) — and those are symbolicated the same way. The basename is what matches, so bundleName: "dist/orders.js" covers a frame at any absolute path your container happens to use. file:// frames, which ESM stacks write, resolve identically; Node's own internals (node:internal/…) are not files and are ignored.

Upload from the same build that produced dist/:

for map in dist/*.js.map; do
bundle="$(basename "${map%.map}")"
curl -X POST https://api.store-pilot.net/ingest/sourcemaps \
-H "X-StorePilot-Key: $STOREPILOT_KEY" \
-H "Content-Type: application/json" \
-d "$(jq -n --arg release "$RELEASE" --arg bundle "$bundle" \
--rawfile map "$map" '{release: $release, bundleName: $bundle, map: $map}')"
done

:::warning One release, one runtime Maps are keyed on (site, release, bundleName) and the bundle name is a basename. If one site reports from both a browser bundle and a Node service, a main.js from each under the same release string is one key with two meanings, and one of them will symbolicate against the wrong map — silently, and plausibly. Use a distinct release per runtime (web-1.4.2, api-1.4.2). :::

Reading the result

Open the issue. When a map matched, the stack trace panel is titled Stack trace (symbolicated · v1.4.2) and each frame shows your original file, line and column.

When nothing matched — no release on the error, no map for that release, or a map that resolved no frames — the raw minified stack is shown instead. That is a normal state, not an error, and it is what you will see for every error reported before you started uploading maps.

A checklist when it does not resolve

  1. Does the error carry a release? Check the Release row on the issue detail page. No release, no match.
  2. Does that release string exactly equal the one you uploaded under? v1.4.2 and 1.4.2 are different builds as far as the match is concerned.
  3. Is the map for the bundle the frame is actually in? Vendor chunks need their own upload.
  4. Was the map uploaded before the error was viewed? Symbolication happens when you open the issue, not when the error arrives — so uploading maps later fixes old errors too, which is the one thing in this list that works in your favour.