Source Maps
Source maps let Rustrak translate minified JavaScript stack traces into their original source locations. When source maps are uploaded, errors show the real file name, line number, and source code — not the minified bundle.
Before and after
Without source maps:
Error: {"type":"Unknown","message":"Unknown Error"}
04 ?
app:///_next/server/chunks/ssr/_0bwf~zv._.js:2:239718
03 ?
app:///_next/server/chunks/ssr/apps_myapp_src_lib_actions_invoices_ts_09hq4k7._.js:2:5956
02 process.processTicksAndRejections
node:internal/process/task_queues:103:5
01 Module.k [as generateMetadata]
app:///_next/server/chunks/ssr/[root-of-the-server]__0fitma~._.js:2:5672With source maps:
Error: Invoice not found
04 getPostedInvoice
src/lib/actions/invoices.ts:84
03 fetchInvoiceData
src/app/invoices/[id]/page.tsx:31
02 process.processTicksAndRejections
node:internal/process/task_queues:103:5
01 generateMetadata
src/app/invoices/[id]/page.tsx:12Same error. One is debuggable, the other isn’t.
How to enable source maps
Source maps are uploaded automatically by the Sentry JavaScript SDK when you use the sourceMapsPlugin (or the Vite/webpack equivalent). No changes to your error tracking code are needed.
Vite
// vite.config.js
import { defineConfig } from 'vite';
import { sentryVitePlugin } from '@sentry/vite-plugin';
export default defineConfig({
build: {
sourcemap: true, // required
},
plugins: [
sentryVitePlugin({
org: 'anything', // any value works, Rustrak ignores it
project: 'my-project', // must match your Rustrak project slug
authToken: 'your-api-token',
url: 'http://localhost:8080', // your Rustrak server URL
}),
],
});webpack
// webpack.config.js
const { sentryWebpackPlugin } = require('@sentry/webpack-plugin');
module.exports = {
devtool: 'source-map', // required
plugins: [
sentryWebpackPlugin({
org: 'anything',
project: 'my-project',
authToken: 'your-api-token',
url: 'http://localhost:8080',
}),
],
};SvelteKit
@sentry/sveltekit wraps the Vite plugin, but names the server URL option
sentryUrl, not url, and the options go at the root level:
// vite.config.js
import { sentrySvelteKit } from '@sentry/sveltekit';
import { sveltekit } from '@sveltejs/kit/vite';
import { defineConfig, loadEnv } from 'vite';
export default defineConfig(({ mode }) => {
// Vite does NOT populate process.env in config files, see note below
const env = loadEnv(mode, process.cwd(), '');
return {
plugins: [
sentrySvelteKit({
org: 'anything', // ignored by Rustrak
project: 'my-project', // must match your Rustrak project slug
authToken: env.SENTRY_AUTH_TOKEN,
sentryUrl: 'http://localhost:8080', // NOT `url` in this SDK
}),
sveltekit(),
],
};
});Older examples nest these under
sourceMapsUploadOptions: { ... }. That whole object is deprecated as of@sentry/sveltekitv10. Move the options to the root level, and renameurltosentryUrlwhile you’re there.
Vite does not load .env files into process.env when evaluating
vite.config.js. If you set SENTRY_AUTH_TOKEN in a .env and read it via
process.env, you’ll get undefined and the upload is silently skipped. Either use
Vite’s loadEnv helper as shown above, or put the values in a
.env.sentry-build-plugin file, which the Sentry plugin reads automatically from
the current working directory.
Source maps are only uploaded during production builds (vite build), never in
vite dev.
What org and project mean in Rustrak
| Option | Env var | Does Rustrak care? |
|---|---|---|
org | SENTRY_ORG | No. Any non-empty string works. |
project | SENTRY_PROJECT | Yes. Must match an existing Rustrak project’s slug (or its numeric ID). |
url (sentryUrl in framework SDKs) | SENTRY_URL | Yes. Must point at your Rustrak server. |
authToken | SENTRY_AUTH_TOKEN | Yes. A Rustrak API token from Settings → API Tokens. |
Why org is ignored
Rustrak has no organizations, and this is by design rather than a missing feature.
In Sentry, an organization separates different customers sharing one server. It groups projects, users, and billing, and it decides which uploaded files each customer is allowed to see. Rustrak is self-hosted: everything on the server is already yours, so there is nothing to separate.
The error reporting protocol never sends an organization either. Your DSN is
key@host/project_id, with no organization in it. So the project, not the
organization, is what identifies your data.
The reason the option exists at all is that sentry-cli checks that the
organization exists before it starts uploading. Rustrak answers that check with
whatever slug you sent, and the upload proceeds. Set it to anything you like, or
leave it as your company name so the config reads sensibly.
Why project is not ignored
The upload happens in two parts, and only the second one looks at your project.
The files themselves are uploaded first, and that step succeeds no matter what
project says. The final step attaches those files to a project, and that is
where a wrong value fails with 404 project not found.
The build does not fail when this happens, so the only symptom is that your stack traces stay minified. See the troubleshooting section below.
Every option can be set through its environment variable instead of the config file; the explicit option wins when both are present.
The
urlmust point to Rustrak. Source map upload is a separate channel from error reporting: your DSN controls where events go, but the build plugin decides where source maps go. If you leaveurlunset, the plugin uploads to Sentry’s hosted service (sentry.io) by default — pointing the DSN at Rustrak does not change this. And ifauthTokenis missing, the upload is silently skipped and the build still succeeds. Other SDKs use the same two options under different names (e.g.sentryUrlfor@sentry/nextjs,--urlforsentry-cli).
How the upload works
The SDK uploads source maps in three steps during your build:
- Capability check — The SDK asks the server what chunk sizes it accepts.
- Chunk upload — Source map files are split into chunks and uploaded. Each chunk is keyed by its SHA-1 hash (content-addressable storage).
- Assembly — The SDK tells the server which chunks form a complete artifact bundle. The server assembles the ZIP and confirms.
From your perspective: run vite build (or webpack) and it happens automatically.
Because the upload runs during the build, the credentials (authToken / url)
have to be available at build time. If you build in Docker or CI, pass the token to
the build itself — a variable set only on the running container comes too late, and
the upload is silently skipped.
Storage
Source map chunks are stored on disk in SOURCEMAP_STORAGE_PATH (default: /data/sourcemaps).
Sizing estimate: Each source map chunk is ~2MB. A typical app with 50 source files uses ~100MB. Scale as needed.
Set a persistent path for production:
SOURCEMAP_STORAGE_PATH=/var/lib/rustrak/sourcemapsMake sure the directory is writable by the Rustrak process.
Production: shared volume required
If you run multiple Rustrak instances behind a load balancer, all instances must share the same SOURCEMAP_STORAGE_PATH. Chunks uploaded to one instance need to be readable by any other instance.
Mount a shared network volume (NFS, AWS EFS, etc.) and set the same SOURCEMAP_STORAGE_PATH on every instance:
# docker-compose.yml (multi-server example)
services:
rustrak:
image: rustrak/rustrak-server:latest
volumes:
- sourcemaps_nfs:/var/lib/rustrak/sourcemaps
environment:
- SOURCEMAP_STORAGE_PATH=/var/lib/rustrak/sourcemapsSingle-server deployments don’t need to worry about this.
Troubleshooting: stack trace is still minified
Work through this checklist:
1. Is sourcemap: true (or devtool: 'source-map') enabled in your build config?
The SDK plugin can only upload source maps that your bundler actually generates. Check your build output for .map files.
2. Did the upload succeed during the build?
The plugin logs upload progress. Look for output like:
[sentry] Uploading source maps...
[sentry] Artifact bundle assembled successfully- No upload output at all → the upload was skipped, almost always because
authTokenis missing. The build still succeeds, so this is easy to miss. - It uploaded, but errors are still minified → check
url. If it isn’t set, source maps go tosentry.ioby default, not to Rustrak. The DSN does not control this. 404 project not foundduring assembly → yourproject/SENTRY_PROJECTdoesn’t match any Rustrak project. Chunks upload fine (that step ignores the project), then the final assembly step rejects them. Use the exact project slug shown in the dashboard URL. Note thatorgis not the problem here, since Rustrak ignores it entirely.
Confirm what actually landed on the server:
# the `anything` segment is the org, which Rustrak ignores
curl -H "Authorization: Bearer YOUR_TOKEN" \
http://localhost:8080/api/0/projects/anything/my-project/files/source-maps/An empty data array means no source maps were ever uploaded for that project.
3. Is SOURCEMAP_STORAGE_PATH writable and persistent?
The default path (/data/sourcemaps) is cleared on restart on some systems. Set a persistent path in production.
4. Are debug_meta entries present in the event?
The Sentry SDK attaches debug_meta.images to each event, linking stack frames to the correct source map via a debug_id. If your SDK version doesn’t emit debug_meta, source map lookup won’t work. Use @sentry/browser 7.x or later.
5. Multi-server deployment: are all instances using a shared volume?
If chunks were uploaded to instance A but the event was processed by instance B, the source map won’t be found. See the shared volume section above.