
Sentry Javascript Bugs
- 81 installs
- 44.5k repo stars
- Updated August 5, 2026
- getsentry/sentry
Does the frontend diff introduce bugs matching patterns from 428 real Sentry production issues?
About
Sentry JavaScript bug pattern review detects high-confidence defects in frontend code by matching against 428 real production issues (524k+ error events). Encodes proven patterns: null/undefined access (158 issues), widget input validation (6), trace view integrity (12), API response assumptions (31), React lifecycle violations (10), AI parsing (2), and array bounds (15). Traces data flow through diffs, component props, hooks, and API shapes to confirm bugs with known fixes. Reports only HIGH and MEDIUM confidence findings with precise locations, triggering inputs, and concrete code fixes. Scope includes Warden findings, PR diffs, branch audits, and production error pattern reviews in frontend code.
- 428 real production issues with 524k+ error events across 93k+ users
- 8 core bug pattern categories with frequency-ranked detection rules
- Traces data flow through props, hooks, API responses, and state transitions
- HIGH/MEDIUM confidence findings only with concrete triggering inputs
- Diff-driven review: Warden, PR, branch audit, or production error patterns
Sentry Javascript Bugs by the numbers
- 81 all-time installs (skills.sh)
- Ranked #483 of 1,352 Code Review & Quality skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/getsentry/sentry --skill sentry-javascript-bugsAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 81 |
|---|---|
| repo stars | ★ 44.5k |
| Last updated | August 5, 2026 |
| Repository | getsentry/sentry ↗ |
What it does
Review React/TypeScript frontend diffs for bug patterns from 428 real production issues affecting 93k+ users.
Who is it for?
Code review on React/TypeScript frontend PRs, Warden audit findings, branch validation, and production error pattern detection.
Skip if: Backend APIs, non-React code, theoretical security analysis, or low-confidence style checks.
When should I use this skill?
Reviewing frontend diff, checking Warden findings, auditing current branch, or analyzing production-error patterns in static/ directory.
What you get
HIGH and MEDIUM confidence bugs are identified before merge with precise locations, triggering conditions, and proven fixes from resolved production issues.
Files
Sentry JavaScript Frontend Bug Pattern Review
Find bugs in Sentry frontend code by checking for the patterns that cause the most real production errors.
This skill encodes patterns from 428 real production issues (201 resolved, 130 ignored, 97 unresolved) generating over 524,000 error events across 93,000+ affected users. These are not theoretical risks -- they are the actual bugs that ship most often, with known fixes from resolved issues.
Scope
Review the code provided by the user, Warden, or the current branch diff. If the user does not provide a target, review the current branch diff. Start from the changed hunk or file, then read outward only as needed to confirm the behavior.
1. Analyze the changed code against the pattern checks below. 2. Use Read and Grep to trace data flow beyond the initial diff when needed. Follow component props, hook return values, API response shapes, and state transitions until the behavior is confirmed. 3. Report only HIGH and MEDIUM confidence findings.
| Confidence | Criteria | Action |
|---|---|---|
| HIGH | Traced the code path, confirmed the pattern matches a known bug class | Report with fix |
| MEDIUM | Pattern is present but context may mitigate it | Report as needs verification |
| LOW | Theoretical or mitigated elsewhere | Do not report |
Step 1: Classify the Code
Determine what you are reviewing and load the relevant reference.
| Code Type | Load Reference |
|---|---|
| Null/undefined property access, optional chaining, object destructuring | references/null-reference-errors.md |
| Dashboard widgets, chart visualization, widget URL generation | references/dashboard-widget-errors.md |
| Trace views, span details, trace tree rendering | references/trace-view-errors.md |
| API calls, response handling, error states, fetch wrappers | references/api-response-handling.md |
| React hooks, context providers, render loops, component lifecycle | references/react-lifecycle-errors.md |
| AI Insights, LLM prompt parsing, gen_ai span data | references/ai-insights-parsing.md |
| Array operations, date/time values, numeric formatting | references/range-and-bounds-errors.md |
If the code spans multiple categories, load all relevant references.
Step 2: Check for Top Bug Patterns
These are ordered by combined frequency and impact from real production data.
Check 1: Null/Undefined Property Access -- 158 issues, 46,337 events
Code accesses a property on a value that may be null or undefined. This is the single most common bug pattern in the Sentry frontend.
Red flags:
- Accessing
.id,.slug,.name,.type,.match,.length,.charCodeAtwithout null checks - Using
object.propertyinstead ofobject?.propertyon data from API responses - Passing API response data directly to utility functions without null validation
- Accessing DOM element properties from
querySelectororuseRefwithout checking if the element exists - Destructuring objects from hooks/stores that may return null during loading states
- Calling
.dispatchEvent()on elements that have been unmounted
Safe patterns:
- Optional chaining:
obj?.property?.nested - Default values:
const value = obj?.field ?? defaultValue - Null guards before function calls:
if (data) { parser.parse(data); } - Early returns for null/undefined parameters in utility functions
Check 2: Dashboard Widget Input Validation -- 6 issues, 90,482 events
Widget visualization components throw when receiving data in unexpected formats.
Red flags:
- Rendering chart components without checking if data contains plottable values
- Calling
getWidgetExploreUrl()for widget types that do not support multiple queries - Passing undefined
fieldvalues toparseFunction()or similar field parsers - Not handling empty API responses in widget data fetchers
Safe patterns:
- Validate data shape before rendering:
if (!hasPlottableValues(data)) return <EmptyState /> - Check widget query count before generating explore URLs
- Guard field parsers:
if (!field) return null
Check 3: Trace View Data Integrity -- 12 issues, 328,482 events
The trace tree renderer and trace detail views encounter data that violates structural assumptions.
Red flags:
- Building trace trees without cycle detection (or detecting cycles but not handling them gracefully)
- Looking up projects by ID from span data without checking if the project is accessible
- Generating trace links without validating
traceSlugis non-empty - Using
captureExceptionin render paths without deduplication (fires every render cycle)
Safe patterns:
- Break cycles by detaching cyclic nodes as orphan roots
- Validate traceSlug before generating links:
if (!traceSlug) return fallbackLink - Deduplicate error captures using a ref:
if (!capturedRef.current) { captureException(...); capturedRef.current = true; } - Check project access before rendering span details
Check 4: API Response Shape Assumptions -- 31 issues, 24,019 events
Frontend code assumes API responses have a specific shape but the response is empty, undefined, or has an unexpected status code.
Red flags:
- Not handling 200 responses with empty bodies (e.g.,
GET /customers/{orgSlug}/returns 200 with no body) - Not handling 402 (Payment Required) status codes in subscription flows
- Not handling 409 (Conflict) status codes in mutation endpoints
- Treating
UndefinedResponseBodyErroras unexpected (it indicates the API returned no parseable body) - Assuming SelectAsync options will always load successfully
Safe patterns:
- Check response body before parsing:
if (!response.body) return null - Handle specific 4xx status codes in catch blocks
- Provide fallback empty states for failed API fetches instead of throwing
Check 5: React Lifecycle Violations -- 10 issues, 2,595 events
Components violate React rendering rules, causing infinite loops or crashes.
Red flags:
- Setting state unconditionally in
useEffectwithout proper dependency arrays - Calling
useOrganization()in components that render before organization context is loaded - Using
useContext()outside the provider boundary - Passing objects as React children instead of strings/elements
- Components that trigger immediate re-render on mount
Safe patterns:
- Always provide dependency arrays for
useEffect - Guard context hooks:
const org = useOrganization(); if (!org) return <Loading /> - Wrap organization-dependent routes in a provider boundary
- Validate element types before rendering:
if (typeof Component !== 'function') return null
Check 6: AI Insights Data Parsing -- 2 issues, 3,005 events
JSON parsing of AI prompt messages and gen_ai span data fails on non-standard formats.
Red flags:
- Calling
JSON.parse()onai.prompt.messagesspan attributes without try-catch - Assuming all AI model responses produce valid JSON
- Not handling the "parts" format for multi-modal AI messages
Safe patterns:
- Wrap all
JSON.parsecalls on external data in try-catch - Check for leading
[or{before parsing - Provide raw-text fallback rendering when parsing fails
Check 7: Array and Bounds Validation -- 15 issues, 3,120 events
Array operations and numeric formatting with values that exceed valid ranges.
Red flags:
- Using
result.push(...largeArray)(crashes when array is too large) - Passing unclamped values to
toLocaleString({maximumFractionDigits: n}) - Constructing Date objects from unvalidated timestamps
- Recursive component rendering without depth limits
Safe patterns:
- Use
concator iterative push for potentially large arrays - Clamp numeric format parameters:
Math.min(100, Math.max(0, precision)) - Validate dates before constructing:
if (isNaN(new Date(ts).getTime())) return fallback - Use iterative rendering with explicit stacks for deeply nested structures
Check 8: Logic Correctness -- not pattern-based
After checking all known patterns above, reason about the changed code itself:
- Does every code path return the correct type (or JSX)?
- Are all branches of conditionals handled (especially missing
else/ default cases in switches)? - Can any prop or state value (null, undefined, empty array, empty string) cause unexpected behavior?
- Are hook dependency arrays correct? Missing deps cause stale closures; extra deps cause infinite loops.
- If this component unmounts mid-async-operation, is cleanup handled?
Only report if you can trace a specific input that triggers the bug. Do not report theoretical concerns.
If no checks produced a potential finding, stop and report zero findings. Do not invent issues to fill the report. An empty result is the correct output when the code has no bugs matching these patterns.
Each code location should be reported once under the most specific matching pattern. Do not flag the same line under multiple checks.
Step 3: Report Findings
For each finding, provide the evidence the review harness needs:
- precise location
- severity and confidence
- concrete triggering input or state
- root cause and consequence
- a matching production precedent when available
- a concrete code fix, preferably as a unified diff when the harness supports it
Fix suggestions must include actual code. Never suggest a comment or docstring as a fix.
Do not prescribe your own output format — the review harness controls the response structure.
Vendored from https://github.com/getsentry/warden-sentry (.agents/skills/sentry-javascript-bugs/).
If this skill needs updating, pull changes from that repository.
AI Insights Parsing Patterns
Contents
- Overview
- Real examples
- Detection checklist
Overview
AI Insights parsing errors account for 2 issues and 3,005 events, but this cluster is escalating as new AI model formats are introduced. The core problem is that JSON.parse is called on AI prompt message data (ai.prompt.messages span attribute) that contains invalid JSON — bad escape characters, non-standard serialization, or plain text where JSON is expected.
Real Examples
[JAVASCRIPT-34D0]: Error parsing ai.prompt.messages (unresolved, 7 variants merged)
Sentry: https://sentry.io/issues/7002181641/ Events: 2,681 | Users: 95
Stacktrace:
./app/views/performance/newTraceDetails/traceDrawer/details/span/eapSections/aiInput.tsx
parseAIMessages
-> JSON.parse(messages)
Underlying: SyntaxError: Bad escaped character in JSON at position 430Root cause: The parseAIMessages function calls JSON.parse on the ai.prompt.messages span attribute. Various LLM providers serialize messages differently and some produce strings with raw newlines, unescaped backslashes, or invalid unicode sequences that are not valid JSON. The function does not catch the parsing error.
Fix pattern:
function parseAIMessages(raw: string): AIMessage[] {
if (!raw) return [];
try {
return JSON.parse(raw);
} catch {
return [{role: 'unknown', content: raw}];
}
}[JAVASCRIPT-379Y]: Error parsing gen_ai messages with parts format (unresolved, escalating)
Sentry: https://sentry.io/issues/7270138341/ Events: 324 | Users: 17
Stacktrace:
./app/views/performance/newTraceDetails/traceDrawer/details/span/eapSections/aiInput.tsx
transformPartsMessages
-> JSON.parse(message)
Underlying: SyntaxError: JSON.parse: unexpected character at line 1 column 2Root cause: The "parts" format handler encounters message data that is not valid JSON. Some AI models serialize multi-modal content (text + images) in non-standard formats. The parser assumes all parts-format messages are JSON but some are plain text or use custom serialization.
Fix pattern:
function transformPartsMessages(raw: string): TransformedMessage {
if (!raw) return {type: 'text', content: ''};
if (!raw.startsWith('[') && !raw.startsWith('{')) {
return {type: 'text', content: raw};
}
try {
return JSON.parse(raw);
} catch {
return {type: 'text', content: raw};
}
}Detection Checklist
- [ ] Is
JSON.parsecalled on AI/LLM span data without try-catch? - [ ] Does the parser handle non-JSON input (plain text, custom formats)?
- [ ] Is there a fallback rendering path for unparseable messages?
- [ ] Are new AI model output formats validated before being passed to parsers?
- [ ] Does the code check for leading
[or{before attempting JSON parse?
API Response Handling Patterns
Contents
- Overview
- Real examples
- Detection checklist
Overview
API response handling errors account for 31 issues and 24,019 events. The Sentry frontend API client makes assumptions about response shapes that break in edge cases: 200 responses with empty bodies, unexpected 4xx status codes, and undefined response bodies from endpoints that return no content.
Key sub-patterns:
1. 200 treated as error (12K events): API returns 200 with empty body, client throws 2. UndefinedResponseBodyError (9.5K events): Response has no parseable body 3. Unhandled 4xx codes (1.5K events): 402, 409 not caught in mutation flows
Real Examples
[JAVASCRIPT-2M6Q]: 200 treated as error: GET /customers/{orgSlug}/ (ignored)
Sentry: https://sentry.io/issues/4290456281/ Events: 12,331 | Users: 168
Root cause: The API client receives a 200 response from /customers/{orgSlug}/ but the body is empty or unparseable. The response handler treats this as an error because it expects a JSON body. The endpoint returns 200 with no body when the customer record exists but has no data to return.
Fix pattern: Handle empty 200 responses as valid in the API client or response wrapper.
if (response.ok && !response.body) {
return null;
}[JAVASCRIPT-2MF5]: UndefinedResponseBodyError: GET /assistant/ 200 (ignored)
Sentry: https://sentry.io/issues/4302193574/ Events: 9,017 | Users: 706
Root cause: Same pattern as above. The /assistant/ endpoint returns 200 with no body. The UndefinedResponseBodyError is thrown by the API client when it cannot parse the response.
Fix pattern: The API endpoint should return 204 No Content when there is no data. On the frontend, handle undefined response bodies without throwing.
[JAVASCRIPT-33RM]: RequestError: PUT subscription 402 (unresolved)
Sentry: https://sentry.io/issues/6861277461/ Events: 1,283 | Users: 678
Root cause: The subscription update endpoint returns 402 (Payment Required) but the frontend does not handle this status code. The error propagates as an unhandled RequestError.
Fix pattern: Handle 402 specifically in subscription mutation flows.
try {
await api.requestPromise(`/customers/${orgSlug}/subscription/`, {method: 'PUT', data});
} catch (error) {
if (error.status === 402) {
addErrorMessage(t('Payment is required to make this change.'));
return;
}
throw error;
}Detection Checklist
- [ ] Does the API client handle 200 responses with empty bodies?
- [ ] Are mutation endpoints (PUT, POST, DELETE) handling 402, 409, 422 status codes?
- [ ] Is
UndefinedResponseBodyErrorcaught and handled gracefully? - [ ] Do async component data loaders provide error states?
- [ ] Are gateway timeout (504) and service unavailable (503) errors shown as user-friendly messages?
- [ ] Do SelectAsync/autocomplete components handle failed option fetches?
Dashboard & Widget Error Patterns
Contents
- Overview
- Real examples
- Detection checklist
Overview
Dashboard widget errors account for 6 issues and 90,482 events. The core problem is widget visualization components that throw exceptions when receiving unexpected data from APIs, rather than rendering graceful empty states. Two dominant patterns:
1. No plottable values: Charts throw when all data is null, empty, or non-numeric (38K events, 3.4K users) 2. Unsupported widget configurations: Functions like getWidgetExploreUrl throw when called with widget types they do not support (51K events)
Real Examples
[JAVASCRIPT-334P]: getWidgetExploreUrl — multiple queries for logs unsupported (unresolved)
Stacktrace:
./app/views/dashboards/widgetCard/widgetCardContextMenu.tsx
actions (line 256)
to: getWidgetExploreUrl(widget, dashboardFilters, selection, organization, Mode.SAMPLES),
./app/views/dashboards/utils/getWidgetExploreUrl.tsx
getWidgetExploreUrl (line 106)
if (widget.queries.length > 1) {
if (traceItemDataset === TraceItemDataset.LOGS) {
Sentry.captureException(new Error(`getWidgetExploreUrl: multiple queries for logs is unsupported...`));
}
}Root cause: The widget context menu eagerly computes the "Open in Explore" URL for all widget types. For log widgets with multiple queries, this is unsupported. The function captures an exception every time the menu is rendered.
Fix pattern: Check widget configuration before computing the URL. Disable the menu item for unsupported configurations.
const canOpenInExplore = widget.widgetType !== WidgetType.LOGS || widget.queries.length <= 1;
if (canOpenInExplore) {
menuOptions.push({key: 'open-in-explore', to: getWidgetExploreUrl(...)});
}[JAVASCRIPT-34B7]: The data does not contain any plottable values (unresolved, 10 variants merged)
Stacktrace:
./app/views/dashboards/widgets/categoricalSeriesWidget/categoricalSeriesWidgetVisualization.tsx
CategoricalSeriesWidgetVisualization
throws Error("The data does not contain any plottable values.")Root cause: Widget visualization throws when the API returns data with no numeric values to plot. This happens when widgets are configured with queries that return empty results, all-null columns, or non-numeric data.
Fix pattern: Replace the throw with an empty-state render.
if (!hasPlottableValues(data)) {
return <EmptyStateWarning>{t('No data available to display.')}</EmptyStateWarning>;
}[JAVASCRIPT-336V]: Unable to fetch releases (resolved)
Root cause: Dashboard widget's release data fetch fails and propagates as an unhandled exception instead of showing an error state.
Fix pattern: Catch fetch errors and surface them as widget-level error states.
Detection Checklist
- [ ] Do chart/visualization components handle empty or null data gracefully?
- [ ] Is widget data validated before being passed to rendering functions?
- [ ] Do utility functions like
getWidgetExploreUrlcheck widget type compatibility? - [ ] Are API fetch errors caught and displayed as widget error states?
- [ ] Do
captureExceptioncalls in render paths have deduplication? - [ ] Is
parseFunction()guarded against undefined field values?
Null Reference Error Patterns
Contents
- Overview
- Real examples
- Detection checklist
Overview
Null/undefined property access is the single most common bug pattern in the Sentry JavaScript frontend, accounting for 158 issues and 46,337 events. These are TypeErrors where code accesses a property (.id, .slug, .charCodeAt, .match, .dispatchEvent, etc.) on a value that is null or undefined.
The most common sources of null values:
1. API response fields that are optional but treated as required 2. Store/hook return values during loading states (before data is hydrated) 3. DOM element lookups (querySelector, useRef) on unmounted elements 4. Function parameters from callers that pass null/undefined for edge cases 5. Destructured objects where the parent object may be null
Real Examples
[JAVASCRIPT-2NQW]: TypeError: null is not an object (evaluating 'e.charCodeAt') (resolved)
Stacktrace:
./app/views/insights/common/components/tableCells/spanDescriptionCell.tsx
SpanDescriptionCell (line 39)
const formatterDescription = useMemo(() => {
return formatter.toSimpleMarkup(rawDescription); // rawDescription is null
}, [moduleName, rawDescription, spanAction, system]);
./app/utils/sqlish/SQLishFormatter.tsx
SQLishFormatter.toFormat (line 49)
tokens = sqlishParser.parse(sql); // sql is null
./app/utils/sqlish/sqlish.pegjs
eI (line 505)
if (input.charCodeAt(peg$currPos) === 40) { // input is nullRoot cause: SpanDescriptionCell passes rawDescription to the SQL parser without checking if it is null. Span descriptions can be null for internal spans or spans with redacted data. The null check at line 51 (if (!rawDescription) return NULL_DESCRIPTION) executes after the useMemo, not inside it.
Fix pattern:
const formatterDescription = useMemo(() => {
if (!rawDescription) return NULL_DESCRIPTION;
if (moduleName !== ModuleName.DB) return rawDescription;
return formatter.toSimpleMarkup(rawDescription);
}, [moduleName, rawDescription, spanAction, system]);[JAVASCRIPT-361B]: TypeError: Invalid alert variant, got undefined (resolved)
Stacktrace:
./app/components/core/alert/alert.chonk.tsx
tokens function
throws TypeError("Invalid alert variant, got undefined")Root cause: The Alert component receives an undefined variant prop. The chonk token function validates the variant but does not provide a default.
Fix pattern:
const resolvedVariant = variant ?? 'info';[JAVASCRIPT-36F2]: Cannot read properties of undefined (reading 'match') (resolved)
Stacktrace:
./app/utils/discover/fields.tsx
parseFunction
field.match(AGGREGATE_PATTERN) // field is undefinedRoot cause: parseFunction is called with an undefined field value from a dashboard widget whose query references a field that no longer exists.
Fix pattern:
function parseFunction(field: string): ParsedFunction | null {
if (!field) return null;
const match = field.match(AGGREGATE_PATTERN);
// ...
}[JAVASCRIPT-34ZH]: Cannot read properties of null (reading 'id') (resolved)
Stacktrace:
./app/views/issueList/issueViews/useSelectedGroupSeachView.tsx
matchingView
view.id // view is null (no matching saved view)Root cause: Hook returns null when no matching saved view exists, but downstream code accesses .id without a null check.
Fix pattern:
const viewId = matchingView?.id;Detection Checklist
- [ ] Does the code access properties on API response data without null checks?
- [ ] Are function parameters validated before use (especially string methods like
.match(),.charCodeAt())? - [ ] Do
useMemo/useCallbackcallbacks check for null inputs before processing? - [ ] Are DOM element refs checked for null before accessing properties?
- [ ] Do hook return values have null guards before property access?
- [ ] Are store values checked during loading/initialization states?
- [ ] Does destructured data handle the case where the parent object is null?
- [ ] Are optional props given default values in component signatures?
Range & Bounds Error Patterns
Contents
- Overview
- Real examples
- Detection checklist
Overview
Range and bounds errors account for 15 issues and 3,120 events. These are RangeErrors from array operations with invalid lengths, numeric formatting with out-of-range parameters, invalid Date construction, and stack overflows from deep recursion.
Key sub-patterns:
1. Invalid array length (2.9K events): push(...spread) on large arrays 2. Stack overflow (99 events): Deep recursion in tree rendering 3. Invalid time values (60 events): Bad timestamps passed to Date constructor 4. Numeric formatting (24 events): maximumFractionDigits out of range
Real Examples
[JAVASCRIPT-35NH]: RangeError: Invalid array length (resolved)
Sentry: https://sentry.io/issues/7121413975/ Events: 911 | Users: 674
Stacktrace:
Array.push (native)Root cause: Code uses result.push(...spans) where spans is a very large array. When the combined size exceeds JavaScript's max array length, push with spread throws a RangeError. This occurs when processing traces with thousands of spans.
Fix pattern:
// Before (crashes on large arrays)
result.push(...spans);
// After (safe for any size)
for (const span of spans) {
result.push(span);
}
// Or: result = result.concat(spans);Actual fix: Resolved (replaced spread with iterative push or concat).
[JAVASCRIPT-358Q]: RangeError: maximumFractionDigits out of range (resolved)
Sentry: https://sentry.io/issues/7130310735/ Events: 24 | Users: 4
Root cause: Number.toLocaleString() receives a maximumFractionDigits value outside the valid range (0-100). The precision is dynamically computed (e.g., Math.ceil(-Math.log10(value))) and can produce negative values or values exceeding 100 for extreme inputs.
Fix pattern:
const precision = Math.min(100, Math.max(0, computedPrecision));
value.toLocaleString(undefined, {maximumFractionDigits: precision});Actual fix: Resolved (clamped the precision value).
[JAVASCRIPT-2WVR]: RangeError: Maximum call stack size exceeded (unresolved)
Sentry: https://sentry.io/issues/5816316247/ Events: 56 | Users: 12
Root cause: Stack overflow from deep recursion when rendering deeply nested data structures (trace trees, nested groups). The browser's call stack limit is exceeded.
Fix pattern: Convert recursive rendering to iterative with an explicit stack.
// Before (recursive)
function renderNode(node: TreeNode): JSX.Element {
return <div>{node.children.map(child => renderNode(child))}</div>;
}
// After (iterative)
function renderTree(root: TreeNode): JSX.Element[] {
const result: JSX.Element[] = [];
const stack = [root];
while (stack.length > 0) {
const node = stack.pop()!;
result.push(<div key={node.id}>{node.label}</div>);
stack.push(...node.children);
}
return result;
}Detection Checklist
- [ ] Is
Array.push(...spread)used on potentially large arrays? - [ ] Are numeric formatting parameters (fraction digits, significant digits) clamped to valid ranges?
- [ ] Are Date objects constructed from validated timestamps?
- [ ] Is there recursive rendering of user-controlled data structures?
- [ ] Are recursive functions guarded with depth limits?
- [ ] Is
toLocaleStringcalled with computed precision values?
React Lifecycle Error Patterns
Contents
- Overview
- Real examples
- Detection checklist
Overview
React lifecycle errors account for 10 issues and 2,595 events. These are violations of React's rendering rules that cause infinite loops, crashes, or context errors. Three main sub-patterns:
1. Infinite re-render loops (2.3K events): Components set state unconditionally in effects 2. Missing context providers (90 events): Hooks used outside their provider boundary 3. Invalid element types (39 events): Objects or undefined passed as React children/components
Real Examples
[JAVASCRIPT-22SP]: InternalError: too much recursion (unresolved)
Sentry: https://sentry.io/issues/3573504746/ Events: 2,332 | Users: 95
Root cause: React's rendering loop enters infinite recursion on the /issues/ route. A component's render function triggers a state update that triggers another render synchronously, causing stack overflow. This is typically caused by a useEffect that sets state without proper dependency arrays or conditions.
Fix pattern: Add dependency arrays and conditional guards to effects.
// Before (infinite loop)
useEffect(() => {
setValue(computeValue(data));
});
// After (conditional, with deps)
useEffect(() => {
const newValue = computeValue(data);
if (newValue !== value) {
setValue(newValue);
}
}, [data]);[JAVASCRIPT-34JC]: useOrganization called but organization is not set (unresolved, 16 variants merged)
Sentry: https://sentry.io/issues/7008432988/ Events: 55 | Users: 36
Stacktrace:
./app/utils/useOrganization.tsx
useOrganization
throws Error("useOrganization called but organization is not set.")Root cause: useOrganization is called in components that render before the organization context has been loaded. 16 variants from different routes were merged, including /settings/account/, /organizations/:orgId/, and various feature pages.
Fix pattern: Return null instead of throwing, or guard with a loading boundary.
// Option 1: Non-throwing hook
function useOrganization(): Organization | null {
const org = useContext(OrganizationContext);
return org ?? null;
}
// Option 2: Guard at route level
function RequireOrganization({children}: Props) {
const org = useOrganization();
if (!org) return <LoadingIndicator />;
return children;
}[JAVASCRIPT-31AY]: Maximum update depth exceeded (resolved, 16 variants merged)
Sentry: https://sentry.io/issues/6688802694/ Events: 38 | Users: 1
Root cause: React's infinite re-render detection fires. 16 variants on different pages. The common pattern is an effect that unconditionally sets state on every render.
Fix pattern: Ensure all useEffect hooks have dependency arrays and state setters are conditional.
Actual fix: Resolved (specific fix not available, but the pattern is consistent).
Detection Checklist
- [ ] Do all
useEffectanduseLayoutEffectcalls have dependency arrays? - [ ] Are state setters inside effects conditional (checking if value actually changed)?
- [ ] Is
useOrganization()called only within routes that have the organization provider? - [ ] Are
useContext()calls inside their respective providers? - [ ] Do dynamic imports and lazy components handle undefined module exports?
- [ ] Are objects being passed as React children? (Should be strings or elements)
- [ ] Is state being set during the render phase (outside effects)?
Trace View Error Patterns
Contents
- Overview
- Real examples
- Detection checklist
Overview
Trace view errors account for 12 issues and 328,482 events -- the highest-impact cluster by far. The trace tree renderer and span detail views make structural assumptions about trace data that break when traces contain cycles, reference inaccessible projects, or lack required fields like trace IDs.
Key sub-patterns:
1. Cycle detection in trace trees (231K events): Parent-child span relationships form cycles 2. Project not found in trace details (94K events): Span references a project the user cannot access 3. Missing trace slug (347 events): Trace context is absent from events, breaking link generation
Real Examples
[JAVASCRIPT-36K9]: Cycle detected in trace tree structure (unresolved)
Sentry: https://sentry.io/issues/7219873856/ Status: unresolved | Events: 231,413 | Users: 79,607
No in-app exception frames (info-level captureMessage on /explore/traces/trace/:traceSlug/).
Root cause: The trace tree builder detects a cycle in span parent-child relationships (A -> B -> A). This fires for every user who views an affected trace, generating enormous volume.
Fix pattern: Handle cycles gracefully by detaching cyclic spans as orphan roots. Rate-limit the diagnostic message per trace ID.
[JAVASCRIPT-2ZX1]: Project not found in useTraceItemDetails (resolved, 3 variants merged)
Stacktrace:
./app/views/performance/newTraceDetails/traceDrawer/details/span/index.tsx
EAPSpanNodeDetails (line 349)
} = useTraceItemDetails({
projectId: node.value.project_id.toString(),
...
./app/views/explore/hooks/useTraceItemDetails.tsx
useTraceItemDetails (line 103)
if ((props.enabled ?? true) && !project && !fetching) {
captureException(
new Error(`Project "${props.projectId}" not found in useTraceItemDetails`)
);
}Root cause: Span data references a project ID that is not in the user's accessible projects. The hook fires captureException on every render cycle without deduplication.
Fix pattern: Deduplicate the error capture. Return a graceful "project not accessible" state.
const capturedRef = useRef(new Set<string>());
if (!project && !fetching && !capturedRef.current.has(props.projectId)) {
capturedRef.current.add(props.projectId);
captureException(new Error(`Project "${props.projectId}" not found`));
}[JAVASCRIPT-3370]: Trace slug is missing (unresolved, 4 variants merged)
Stacktrace:
./app/components/events/interfaces/performance/spanEvidenceKeyValueList.tsx
makeTransactionNameRow (line 610)
const traceSlug = event.contexts?.trace?.trace_id ?? '';
const eventDetailsLocation = generateLinkToEventInTraceView({traceSlug, ...});
./app/utils/discover/urls.tsx
generateLinkToEventInTraceView (line 82)
if (!traceSlug) {
Sentry.captureException(new Error('Trace slug is missing'));
}Root cause: Events without trace context (no contexts.trace.trace_id) produce an empty traceSlug. The link generator detects the problem but generates a broken link anyway.
Fix pattern: Check traceSlug before calling the link generator. Show a fallback when trace context is missing.
const traceSlug = event.contexts?.trace?.trace_id;
if (!traceSlug) {
return makeRow(t('Transaction'), event.title);
}Detection Checklist
- [ ] Does trace tree building handle cycles (parent-child loops)?
- [ ] Are project IDs from span data validated against accessible projects?
- [ ] Is
traceSlugchecked for emptiness before generating trace links? - [ ] Do
captureExceptioncalls in hooks use deduplication (refs, sets)? - [ ] Are error captures in render paths guarded against firing every render cycle?
- [ ] Do trace detail components handle missing/inaccessible spans gracefully?