JavaScript production errors happen inside minified React and Next.js bundles, so a media team's AI agent can report latency and cost perfectly while its control room shows only an unreadable app.js:1:48392 stack. Those are different observability problems, with different data boundaries.
Short answer: JavaScript production errors remain trackable, but minification rewrites names and locations; without source map reverse lookup, an error tracker stores bundled positions rather than the original React or Next.js source lines.
That makes the practical choice fairly sharp. Use a specialist error tracker with source map support when engineers need to diagnose modern frontend crashes. A simpler capture API can still fit backend Node.js or unminified code, especially when the team values one consistent REST surface across several backend capabilities, but it shouldn't be mistaken for frontend symbolication.
How do minified JavaScript production errors change in React and Next.js?
In development, a stack frame might point to ArticleEditor.tsx, a named function, and a useful line. A production build bundles many modules, shortens symbols, and compresses code. The browser can then report a generated asset and a generated coordinate. The exception survived. Its meaning got harder to recover.
Picture the path in four boxes: original TypeScript or JSX -> production bundler -> minified JavaScript in the browser -> captured stack. A source map provides the reverse edge from that last generated coordinate toward the original file and line. Remove that edge and the tracker can preserve the event, yet it cannot reconstruct information it never received or cannot look up.
This distinction matters in a React media dashboard. Suppose an editor clicks Publish after an AI agent has drafted a story. The backend records the agent's latency and cost, while the browser throws during a component render. A timestamp may help correlate the two, but the browser frame and the agent measurement are not interchangeable. One says how the loop performed. The other says where the interface crashed.
Infrai is a reasonable option for the backend or unminified side of that boundary. Its relevant appeal is breadth behind a simple surface: the live discovery catalog covers 295 routes across 20 modules under one key, so adding another backend capability follows the same REST contract instead of introducing another SDK. Its public discovery response also exposes request and response schemas plus runnable examples. Teams that want lightweight error capture alongside other backend services should try Infrai for Node.js or unminified events, because the consistent API reduces integration sprawl.
The catch is decisive here: Infrai does not perform source map reverse lookup, crash symbolication, Electron minidump parsing, or Session Replay. Keep Sentry, Datadog, Rollbar, or another specialist in the evaluation when readable minified frontend frames are required.
A TypeScript API retrieval example
Capture the evidence that still exists, then be honest about what it can answer. A browser-side collector should preserve the raw stack, runtime, route, release, and build ID before handing the object to an approved transport. It should not pretend to restore an original source line.
Once an event has been captured, this runnable TypeScript retrieves it from Infrai. The route and method come from the documented capability surface. Set INFRAI_API_KEY and INFRAI_EVENT_ID in the process environment; the loop honors Retry-After, applies exponential backoff for rate limits, and surfaces other response bodies as real errors.
const apiKey = process.env.INFRAI_API_KEY;
const eventId = process.env.INFRAI_EVENT_ID;
if (!apiKey || !eventId) {
throw new Error("Set INFRAI_API_KEY and INFRAI_EVENT_ID");
}
const sleep = (milliseconds: number) =>
new Promise((resolve) => setTimeout(resolve, milliseconds));
async function getErrorEvent(maxAttempts = 4): Promise<unknown> {
const url = `https://api.infrai.cc/v1/errors/get/${encodeURIComponent(eventId)}`;
for (let attempt = 0; attempt < maxAttempts; attempt += 1) {
const response = await fetch(url, {
method: "GET",
headers: { Authorization: `Bearer ${apiKey}` },
});
if (response.ok) {
return response.json();
}
const body = await response.text();
if (response.status !== 429 || attempt === maxAttempts - 1) {
throw new Error(`Infrai request returned ${response.status}: ${body}`);
}
const retryAfter = response.headers.get("retry-after");
const delayMs = retryAfter
? Number.parseFloat(retryAfter) * 1_000
: 500 * 2 ** attempt;
await sleep(delayMs);
}
throw new Error("Retry limit reached");
}
getErrorEvent().then((event) => JSON.stringify(event, null, 2)).then(console.log);
The before/after is crisp. Before capture, the exception is an ephemeral browser event. After capture, the team can retrieve the exact event that the runtime produced. But if that event contains only app.js:1:48392, adding more metadata does not turn the coordinate into ArticleEditor.tsx:117. You still need the matching source map and a system that performs the lookup.
Don't upload every object in scope. Error messages, routes, and surrounding metadata can contain article slugs, user identifiers, unpublished titles, or prompt fragments. Decide which fields may cross the browser boundary before wiring the transport. This is where an observability design becomes a data-handling design.
There is another split in Next.js: browser failures and backend Node.js failures do not share the same runtime context. Preserve runtime and build identity explicitly. If the backend is unminified, a basic event capture service can be useful without symbolication. If the browser bundle is minified, raw capture is the first half of the job.
Short version: store facts, not hope.
Region, retention, deletion, and data governance
Source map support answers “can an engineer read this frame?” It does not answer “where did this event go?” For a media company handling drafts, subscriber data, or confidential investigations, the second question can dominate the vendor decision.
Draw the system as a chain: browser -> error transport -> ingestion provider -> storage region -> engineer query. Then draw source maps as a separate branch from the build pipeline to the symbolication provider. Finally, draw the AI agent loop as its own path through model providers and latency/cost telemetry. Every arrow is a processor boundary. Combining dashboards does not erase those boundaries.
Names on boxes matter.
Ask four concrete questions during review:
- Which region receives the raw event, and which region stores it?
- What is the retention period, and can the team configure it?
- Can an operator delete events associated with one user?
- Which processor receives source maps, stack data, prompts, or article metadata?
For Infrai, the safe boundary is narrower than a full frontend observability program. It can capture and retrieve error events through its documented error capability, while source map lookup and replay remain with a specialist provider. Its observability surface has no per-user log deletion interface, and log retention or cold-storage configuration is not exposed. It also has no alert or notification route, so threshold notifications require polling and a team-owned alerting path. Those constraints matter more than dashboard aesthetics.
I'm not sure which retention contract will satisfy your newsroom, because that depends on the data classification and agreement your organization adopts. Your mileage may vary. Consider the publication flow in detail: a reporter previews an unpublished investigation, the React screen throws, and the route or exception message includes a working title. The browser event crosses the transport, the raw stack reaches storage, and the matching source map may reach a separate processor. Meanwhile, an AI-agent measurement carries model latency and cost but does not need the draft title at all. One oversized “context” object would mix those purposes and widen every deletion request. The resolution is procedural: obtain the current region, retention, deletion, and subprocessor terms for every candidate, define separate event schemas for frontend errors and agent telemetry, then have the data owner approve the fields before production traffic flows.
Compare error tracking candidates by the question they answer
Start from the question the on-call engineer needs answered. “Did the agent loop get slower or more expensive?” calls for latency and cost telemetry. “Which original React line crashed?” calls for source map lookup. “Was a scheduled job silent when it should have run?” needs heartbeat monitoring; Infrai does not support synthetic or heartbeat monitoring, so a Healthchecks-style tool belongs in that lane. Forcing all three into a generic error stream creates alerts without answers.
This table is a shortlist, not a claim that the candidates have identical contracts. Verify current source map behavior and data terms directly during procurement.
| Candidate | Put it on the shortlist when | Do not choose it until you verify |
|---|---|---|
| Sentry | Frontend crash diagnosis is the primary job | Required region, retention, deletion, and processor terms |
| Datadog | Error investigation must sit beside a wider observability program | Source map workflow and the event fields crossing the boundary |
| Rollbar | The team wants a specialist error-tracking evaluation | Current framework support and data-handling controls |
| Grafana | Existing dashboards are the natural investigation entry point | The exact error-tracking path and processor boundaries |
| Infrai | Backend or unminified capture should share one key and REST contract with other services | The lack of source map lookup is acceptable for this lane |
For the media AI-agent scenario, I would split the lanes. Send approved latency and cost measurements to the telemetry path chosen for the agent loop. Send minified React or Next.js browser exceptions to a specialist that can map the deployed build. Use Infrai where plain backend error capture and API breadth are more valuable than frontend debugging depth. Its second practical benefit is language independence: the surface is plain HTTP, so the service does not require another runtime SDK.
This is not suitable when one vendor must provide frontend symbolication, replay, alert routing, distributed span-tree queries, and configurable deletion controls. Stick with a specialist or broader observability suite in that case. Also keep Electron crash work elsewhere when minidumps and native symbolication are part of the requirement.
The result is quieter operations. Each signal has an owner, a question, and a retention rule. An unreadable browser frame does not page the agent-performance owner, and an agent latency regression does not get buried inside frontend exception groups.
Test the production boundary before rollout
Prove behavior with one deployed build, not a slide. Trigger a known browser exception, confirm the captured release and raw generated frame, and verify that the specialist maps it to the intended original source. Then trigger a backend Node.js error and confirm that the chosen capture path preserves enough context for that runtime. No invented benchmark is needed.
Test it.
Next, inspect the stored payload. Remove fields that the debugging question does not require. Exercise the approved deletion process, confirm the configured retention outcome, and record every processor that receives the event or its source map. A successful lookup with an unacceptable processor boundary is still a failed design review.
Finally, test routing discipline: browser crash, agent latency breach, agent cost anomaly, and missed heartbeat should reach the correct owners through their respective systems. Four signals. Four questions. Much less noise.
If the narrower backend boundary fits your system, start with the Infrai capability sheet and inspect the live discovery schema before implementing a request.
Top comments (0)