Skip to content

sourcemaps inject drops dart2js extension fields (x_org_dartlang_dart2js, engine) from Flutter Web sourcemaps #3328

@buenaflor

Description

@buenaflor

Environment

CLI Version

3.5.0og

Operating System and Architecture

  • macOS (arm64)

Operating System Version

macOS 15.7.7

Reproduction Steps

main.dart.js

The file extension here is a json but it's actually .map - GitHub rejects .map uploads ... you can change it after downloading
main.dart.js.json

CLI Command

sentry-cli sourcemaps inject main.dart.js main.dart.js.map

Exact Reproduction Steps

  1. Build any Flutter Web app with sourcemaps: flutter build web --source-maps. The attached main.dart.js / main.dart.js.map are a minimal stand-in for build/web/main.dart.js(.map) — the map contains the dart2js-specific top-level fields engine and x_org_dartlang_dart2js (values excerpted from a real build, truncated for size; in a real app x_org_dartlang_dart2js is several hundred KB).
  2. Run sentry-cli sourcemaps inject main.dart.js main.dart.js.map (or sentry-cli sourcemaps inject build/web, which is what sentry_dart_plugin effectively does).
  3. Inspect the sourcemap: jq 'keys' main.dart.js.map.

Map before inject:

{
  "version": 3,
  "engine": "v2",
  "file": "main.dart.js",
  "sourceRoot": "",
  "sources": ["org-dartlang-sdk:///lib/main.dart"],
  "names": ["main"],
  "mappings": "AAAAA;AACA",
  "x_org_dartlang_dart2js": {
    "minified_names": { "global": "A,20845,A0,1916,…", "instance": "A,20845,A0,1916,…" },
    "frames": "uzHA+Jeg29ByB;sCAKAAyB;…"
  }
}

Map after inject:

{"version":3,"file":"main.dart.js","sources":["org-dartlang-sdk:///lib/main.dart"],"sourceRoot":"","names":["main"],"mappings":";;AAAAA;AACA","debugId":"7d30e0ab-d257-5872-8a48-006edfd6b3e5"}

Results

Expected Results

inject adds the debugId field (and shifts mappings to account for the snippet prepended to the JS) while leaving all other sourcemap content intact — in particular generator-specific extension fields.

Actual Results

The sourcemap is fully decoded and re-encoded, which silently drops every non-standard top-level field:

  • x_org_dartlang_dart2js — dart2js's extension containing minified_names (global/instance minified-name tables) and frames (inlining records). In the future this is required to deobfuscate minified Dart names and expand inlined frames; on a real Flutter Web build this is ~620 KB of data (e.g. 3,298,985 → 2,680,105 bytes for the example app's main.dart.js.map).
  • engine — Flutter's engine sourcemap marker.

Root cause (sentry-cli master): in src/utils/sourcemaps.rs, inject_debug_ids → Case 3 (external sourcemap) does

let sm = sourcemap::decode_slice(&sourcemap_file.contents)?;   // parse with rust-sourcemap
// ... adjust_regular_sourcemap(): adjust_mappings(&adjustment_map)
sourcemap.set_debug_id(Some(debug_id));
sourcemap.to_writer(sourcemap_file_contents)?;                  // re-serialize

rust-sourcemap's SourceMap struct only models the standard spec fields (file, tokens, names, source_root, sources, sources_content, ignore_list, debug_id), so everything else is discarded on to_writer.

Logs

> Searching main.dart.js
> Found 1 file
> Searching main.dart.js.map
> Found 1 file
> Analyzing 2 sources
> Injecting debug ids

Source Map Debug ID Injection Report
  Modified: The following source files have been modified to have debug ids
    7d30e0ab-d257-5872-8a48-006edfd6b3e5 - main.dart.js
  Modified: The following sourcemap files have been modified to have debug ids
    7d30e0ab-d257-5872-8a48-006edfd6b3e5 - main.dart.js.map

Metadata

Metadata

Assignees

No one assigned

    Labels

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions