Skip to content
Everframe Docs
Documentation

Source maps & R8 mappings

Tag the exact build, upload its private mapping artifacts from trusted CI, and keep Raw frames available beside the mapped result.

Updated

Everframe can process three kinds of private build artifact:

RuntimeReport identityUpload command
React and Webcontext.app.build from appBuildsourcemaps upload
React Native with Hermespayload.crash.jsBundle from jsBundlesourcemaps upload-hermes
Android JVM with R8payload.crash.jvm.mappingId from r8MappingIdr8 upload

The identity embedded in the shipped app must exactly match the identity passed to the uploader. Everframe does not guess from an app version, filename, or the newest upload. Existing reports without an identity cannot be tagged later.

The uploader currently lives in the private Everframe workspace. Run it from a Everframe checkout after building @everframe/cli; there is no public npx installation implied by these examples.

Use the right credentials

Your app uses a public SDK ingest key. It is expected to ship in browser or app code and can submit reports only:

const PUBLIC_SDK_KEY = 'evf_live_PUBLIC_EXAMPLE';

Artifact upload uses a different credential: an API token with explicit artifacts:write scope and access to the project that owns the target app. Keep it in trusted CI as the masked EVERFRAME_API_TOKEN environment variable. Never put this token in an app bundle, a NEXT_PUBLIC_* variable, source code, or a CLI argument. EVERFRAME_APP_ID is the target app UUID, not an SDK key.

: "${EVERFRAME_API_TOKEN:?Set the masked artifacts:write token}"
: "${EVERFRAME_APP_ID:?Set the target app UUID}"
export EVERFRAME_API_URL='https://api.everframe.dev/api/v1'

pnpm --filter @everframe/cli... build

Treat a nonzero uploader exit as a release failure. Repeating an upload with the same identity and identical artifacts resumes safely. Reusing an identity for different bytes returns 409 build_conflict; assign a new identity and rebuild the app.

Web and React

Generate a unique build ID before compiling and pass it to both the SDK and the upload job. Build IDs are exact, nonblank strings of at most 200 UTF-16 code units:

import { EverframeProvider } from '@everframe/react';

<EverframeProvider config={{
  apiKey: PUBLIC_SDK_KEY,
  appVersion: '2.4.0',
  appBuild: WEB_BUILD_ID,
}}>
  <App />
</EverframeProvider>

For @everframe/web, set the same appBuild in init(). Then upload the exact JavaScript and adjacent .js.map files produced by that build:

node packages/cli/dist/index.js sourcemaps upload \
  --app-id "$EVERFRAME_APP_ID" \
  --build "$WEB_BUILD_ID" \
  --dir dist/assets \
  --url-prefix https://app.example.com/assets/ \
  --delete-after-upload

--url-prefix must be the exact deployed origin and path represented by --dir, including any CDN origin or base path, and must end in /. The CLI pairs adjacent JavaScript and map files, reports JavaScript without a map, and rejects orphan maps or an empty upload.

--delete-after-upload removes maps only after the server confirms the build is ready and the CLI rechecks their hashes. It never deletes JavaScript. Do not rebuild after upload: deploy those same JavaScript bytes, and ensure no source maps remain in any public deploy directory or CDN payload.

React Native Hermes

Give every changed JavaScript or OTA build its own identity. Android and iOS must use distinct IDs even when they share an app version. Build IDs use the same nonblank 200-unit limit as web builds; bundle names must match [A-Za-z0-9][A-Za-z0-9._-]{0,127}:

import { EverframeProvider } from '@everframe/react-native';

<EverframeProvider config={{
  apiKey: PUBLIC_SDK_KEY,
  jsBundle: {
    buildId: HERMES_BUILD_ID,
    bundleName: 'index.android.bundle',
  },
}}>
  <App />
</EverframeProvider>

Upload the final Hermes bytecode and the final composed Metro/Hermes map from the same release build. A Metro-only intermediate map cannot translate Hermes bytecode offsets.

node packages/cli/dist/index.js sourcemaps upload-hermes \
  --app-id "$EVERFRAME_APP_ID" \
  --build "$HERMES_BUILD_ID" \
  --platform android \
  --bundle-name index.android.bundle \
  --bundle android/app/build/generated/assets/react/release/index.android.bundle \
  --source-map android/app/build/generated/sourcemaps/react/release/index.android.bundle.map

For iOS, use --platform ios, the actual bundle name (commonly main.jsbundle), the final HBC inside the built app resources, and the explicit composed map written to SOURCEMAP_FILE. The Hermes uploader preserves both input files and rejects --delete-after-upload; exclude the map from the app, OTA package, and public artifacts yourself.

The jsBundle configuration and handled-error details described here are from the current source tree. A JS-only update cannot add missing native bridge support; rebuild the host app with matching JS and native SDK components.

Android R8

Generate the mapping ID before compiling the optimized build, embed it in EverframeConfig, and retain that build’s final mapping.txt:

import dev.everframe.config.EverframeConfig

EverframeConfig(
    appId = "evf_app_PUBLIC_EXAMPLE",
    sdkKey = "evf_live_PUBLIC_EXAMPLE",
    r8MappingId = BuildConfig.EVERFRAME_R8_MAPPING_ID,
)

Upload the mapping from trusted CI:

node packages/cli/dist/index.js r8 upload \
  --app-id "$EVERFRAME_APP_ID" \
  --mapping-id "$EVERFRAME_R8_MAPPING_ID" \
  --mapping app/build/outputs/mapping/release/mapping.txt

The mapping ID must match the optimized binary and the pattern [A-Za-z0-9][A-Za-z0-9._-]{0,127}. Everframe retraces Java and Kotlin JVM frames only. Android NDK crashes and ELF symbols are not collected or processed by this workflow.

Enable processing on the API

Artifact upload and frame processing are separate. Apply the API migrations, then deploy the entire API dist output together, including dist/processor-child.js and its shared chunks. Set this on the API instance and restart it:

SOURCE_MAP_WORKER_ENABLED=true

The worker is disabled by default. For R8, provision Java 17 or newer and the pinned R8 9.4.17 runtime, then also set R8_WORKER_ENABLED=true; that flag does not start the shared worker by itself. Web and Hermes processing need only the shared flag.

Reports can arrive before their artifacts or while processing is disabled. Once the exact upload is ready, the worker can enrich retained reports without changing the raw envelope, report ID, client fingerprint, occurrence count, or webhook history.

One late-upload recovery path remains unfinished: a completed processor-v1 result is not reopened solely because maps for retained generic cause frames arrive later. Do not treat the current branch as end-to-end completion of generic cause mapping or its optimized dashboard presentation.

Read and troubleshoot results

The error detail stack opens in Mapped mode when mapped web or Hermes frames are available, or Retraced mode for R8 output. Choose Raw at any time to see the frames captured by the SDK. A partial result can mix mapped and raw frames; Everframe never substitutes a nearby build’s artifact.

For Web and React, maps can also support opt-in server grouping and release-aware regression handling. Those controls, their additional worker gates, and their limits are covered in Error triage & releases.

ResultWhat to check
missing_build or missing_js_bundleEmbed the exact web appBuild or Hermes jsBundle identity before compiling. Untagged reports cannot infer it later.
missing_artifactsConfirm the token’s project access, target app UUID, exact build or mapping ID, upload completion, and retention.
Web missing_artifact or no_mappingCompare the full captured frame URL with --url-prefix, including CDN origin and base path, and confirm the throw-site map was emitted.
Hermes no_mappingConfirm the uploaded bytecode and map are the final composed pair from the shipped build.
409 build_conflict or expired identityUse a fresh ID and rebuild. Do not reuse an ID for changed bytes.
Pending indefinitelyCheck migrations, SOURCE_MAP_WORKER_ENABLED=true, the deployed dist/processor-child.js, private blob availability, and worker logs.
R8 stays rawAlso check R8_WORKER_ENABLED=true and the server’s Java/R8 runtime.
401 or 403Use a non-revoked API token with artifacts:write and project access, never the public SDK key.
503 processing_limitLet the CLI’s bounded retry honor Retry-After, or retry after processor capacity is available.
invalid_map or another failed resultCheck artifact format and limits. Raw frames remain available.

Current limits are 32 MiB per map, 256 MiB per build, 500 artifacts per web build, and 1 GiB of stored or reserved artifacts per project. Ready artifacts expire after 90 days; incomplete uploads expire after 24 hours, and expired identities cannot be reused.

This workflow does not process Apple dSYMs, native iOS crashes, Android NDK crashes, or ELF symbols. Keep the platform crash and symbol files required by your other crash tooling.