Understanding Source Map v3 Specification and Formats
The Source Map v3 specification defines the standardized JSON schema for mapping minified or transpiled code back to original sources. This guide breaks down the v3 structure, VLQ encoding mechanics, and format routing strategies essential for accurate stack trace resolution in Source Map Generation & Stack Trace Debugging workflows.
Key implementation requirements:
- Strict v3 JSON schema compliance across parsers
- VLQ (Variable Length Quantity) encoding/decoding logic
- Format routing: inline, external, and hidden
- Browser and Node.js resolution precedence
Source Map v3 JSON Schema Breakdown
Define mandatory and optional fields per the v3 spec to ensure parser compatibility across observability platforms. The version field must be exactly 3. Any deviation triggers legacy fallbacks or hard parser failures.
The sources array requires normalized relative or absolute paths. These paths resolve against the map’s location or the sourceRoot field. The names array maps identifier tokens for precise AST reconstruction during symbolication.
The mappings string uses VLQ encoding for line/column offsets. Each segment represents a coordinate shift relative to the previous mapping. Configure production schema generation via Configuring Webpack for Production Source Maps.
{
"version": 3,
"file": "app.min.js",
"sources": ["src/index.ts"],
"names": ["init", "render"],
"mappings": "AAAA,SAASA,EAAKC,CAAC,CAAC,CAAC"
}
This structure demonstrates required top-level keys and the base64 VLQ mapping string format required for strict parser compliance.
VLQ Encoding Mechanics and Decoding Workflow
Base64-encoded VLQ sequences translate directly to exact source coordinates for stack trace normalization. The encoding relies on a fixed character set: A-Z, a-z, 0-9, +, /.
Each character represents 6 bits. The least significant bit acts as a continuation flag. If set to 1, the next character belongs to the same integer. If 0, the sequence terminates.
Signed integers use two’s complement shifting. The final bit determines the sign before right-shifting by one position. Apply this logic to parse every comma-separated segment in the mappings string.
const BASE64 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
function decodeVLQ(str) {
let result = 0, shift = 0, digit;
do {
digit = BASE64.indexOf(str.shift());
result |= (digit & 31) << shift;
shift += 5;
} while (digit & 32);
return (result & 1) ? -(result >> 1) : (result >> 1);
}
This algorithm handles continuation bits and reconstructs signed coordinate offsets. It forms the core of any custom symbolication pipeline.
Source Map Format Routing and Resolution
Route formats based on environment constraints and security requirements. Inline maps append //# sourceMappingURL=data:application/json;base64,... directly to the bundle. This eliminates network requests but increases payload size.
External maps reference a separate asset using //# sourceMappingURL=app.js.map. Host these on a CDN or artifact registry. This approach keeps production bundles lean and isolates source code exposure.
Hidden maps omit the directive entirely. Serve them via HTTP headers or a secure artifact pipeline. Use Vite Build Settings for Accurate Stack Traces for automated dev/prod format toggling.
Validation, Parsing, and Error Handling
Implement strict validation routines to catch malformed v3 maps before deployment to staging or production. Validate against sourcemap-validator or compile an ajv schema at build time.
Handle sourcesContent carefully. A null value differs from an omitted key. Omission breaks offline symbolication. Cross-reference sources length with mappings segment counts to prevent index drift.
Apply Converting eval source maps to inline format when migrating legacy eval-based builds to standard v3 compliance.
const Ajv = require('ajv');
const ajv = new Ajv();
const schema = {
type: 'object',
required: ['version', 'sources', 'mappings'],
properties: {
version: { const: 3 },
sources: { type: 'array', items: { type: 'string' } },
mappings: { type: 'string', pattern: '^[A-Za-z0-9+/=,;]+$' }
}
};
const validate = ajv.compile(schema);
if (!validate(sourceMapJSON)) {
throw new Error(`Invalid v3 map: ${JSON.stringify(validate.errors)}`);
}
This validation block enforces structural integrity and catches malformed VLQ sequences early in the CI/CD pipeline.
Common Pitfalls and Resolution Strategies
- Mismatched
sourcesarray length andmappingssegment count: Parsers fail when generated segments exceed declared source files. This causes index-out-of-bounds errors during symbolication. Normalize paths before generation. - Incorrect MIME type for external
.mapresponses: Serving.mapfiles astext/plaintriggers CORS or content-type rejection. Configure your server to returnapplication/json. - Omitting
sourcesContentin CI/CD artifact uploads: Remote symbolication services cannot reconstruct original code without embedded content. Error reporting accuracy degrades and breakpoint mapping breaks.
Frequently Asked Questions
Why does the v3 spec require version: 3 exactly?
It ensures strict parser compatibility and prevents fallback to legacy v1/v2 formats. Older versions lack sourcesContent and names support, breaking modern stack trace resolution.
How do I validate a generated .map file against the v3 schema?
Use ajv with the official JSON schema or run source-map-validator in CI pipelines. This catches malformed VLQ sequences and missing required fields before deployment.
When should I use inline vs external source maps? Use inline maps for rapid local debugging. Switch to external maps for production to reduce payload size and enable secure, separate hosting behind authentication layers.
What causes mappings string parsing failures?
Corrupted base64 padding, unescaped commas, or incorrect continuation bit handling during minification. Post-build transformations often strip or mangle these sequences if not configured correctly.