diff --git a/static/app/components/stackTrace/issueStackTrace/index.spec.tsx b/static/app/components/stackTrace/issueStackTrace/index.spec.tsx
index 718dbbbb785f..ccd17952dc97 100644
--- a/static/app/components/stackTrace/issueStackTrace/index.spec.tsx
+++ b/static/app/components/stackTrace/issueStackTrace/index.spec.tsx
@@ -118,6 +118,36 @@ describe('IssueStackTrace', () => {
expect(container).toBeEmptyDOMElement();
});
+ it('renders exception details when no structured stacktrace is available', async () => {
+ const event = EventFixture({
+ platform: 'python',
+ projectID: '1',
+ entries: [{type: 'exception' as const, data: {values: []}}],
+ });
+
+ render(
+
+ );
+
+ expect(await screen.findByText('Stack Trace')).toBeInTheDocument();
+ expect(screen.getByText('ValueError')).toBeInTheDocument();
+ expect(screen.getByText('bad value')).toBeInTheDocument();
+ expect(screen.getByText('No stacktrace found.')).toBeInTheDocument();
+ });
+
it('persists raw and minified display selections per project', async () => {
const {event, stacktrace} = makeStackTraceData();
const minifiedStacktrace = {
diff --git a/static/app/components/stackTrace/issueStackTrace/index.tsx b/static/app/components/stackTrace/issueStackTrace/index.tsx
index a56026a22b53..31f7ac315cb5 100644
--- a/static/app/components/stackTrace/issueStackTrace/index.tsx
+++ b/static/app/components/stackTrace/issueStackTrace/index.tsx
@@ -263,9 +263,11 @@ function IssueStackTraceContent({
)}
-
-
-
+ {exc.stacktrace && (
+
+
+
+ )}
- {idx === firstVisibleExceptionIndex ? (
+ {exc.stacktrace && idx === firstVisibleExceptionIndex ? (
diff --git a/static/app/components/stackTrace/issueStackTrace/utils.ts b/static/app/components/stackTrace/issueStackTrace/utils.ts
index 02d1bbbfe0a9..90d6cd5285b2 100644
--- a/static/app/components/stackTrace/issueStackTrace/utils.ts
+++ b/static/app/components/stackTrace/issueStackTrace/utils.ts
@@ -2,11 +2,9 @@ import {displayRawContent as rawStacktraceContent} from 'sentry/components/event
import type {StackTraceView} from 'sentry/components/stackTrace/types';
import type {Event, ExceptionValue} from 'sentry/types/event';
import {EntryType} from 'sentry/types/event';
-import type {StacktraceType} from 'sentry/types/stacktrace';
interface IndexedExceptionValue extends ExceptionValue {
exceptionIndex: number;
- stacktrace: StacktraceType;
}
/**
@@ -28,9 +26,7 @@ export function getOrderedExceptions(
isNewestFirst: boolean,
view: StackTraceView
): IndexedExceptionValue[] {
- const indexed = values
- .map((exc, exceptionIndex) => ({...exc, exceptionIndex}))
- .filter((exc): exc is IndexedExceptionValue => exc.stacktrace !== null);
+ const indexed = values.map((exc, exceptionIndex) => ({...exc, exceptionIndex}));
return isNewestFirst && view !== 'raw' ? indexed.reverse() : indexed;
}
diff --git a/static/app/components/stackTrace/stackTraceProvider.tsx b/static/app/components/stackTrace/stackTraceProvider.tsx
index 0724a687c381..bd285a305b21 100644
--- a/static/app/components/stackTrace/stackTraceProvider.tsx
+++ b/static/app/components/stackTrace/stackTraceProvider.tsx
@@ -1,6 +1,7 @@
import {useCallback, useMemo, useState} from 'react';
import {isExpandable as frameHasExpandableDetails} from 'sentry/components/events/interfaces/frame/utils';
+import {NoStackTraceMessage} from 'sentry/components/events/interfaces/noStackTraceMessage';
import {getLastFrameIndex} from 'sentry/components/events/interfaces/utils';
import type {Event} from 'sentry/types/event';
import type {PlatformKey} from 'sentry/types/platform';
@@ -12,6 +13,13 @@ import {StackTraceContext, useStackTraceViewState} from './stackTraceContext';
import type {StackTraceContextValue} from './stackTraceContext';
import type {StackTraceProviderProps} from './types';
+const EMPTY_STACKTRACE: StacktraceType = {
+ frames: [],
+ framesOmitted: null,
+ hasSystemFrames: false,
+ registers: null,
+};
+
function getDefaultPlatform(stacktrace: StacktraceType, event: Event): PlatformKey {
const framePlatform = stacktrace.frames?.find(frame => !!frame.platform)?.platform;
return event.platform ?? framePlatform ?? 'other';
@@ -33,8 +41,10 @@ export function StackTraceProvider({
}: StackTraceProviderProps) {
const {isMinified, isNewestFirst, view} = useStackTraceViewState();
- const activeStacktrace =
- isMinified && minifiedStacktrace ? minifiedStacktrace : stacktrace;
+ let activeStacktrace = stacktrace ?? EMPTY_STACKTRACE;
+ if (isMinified && minifiedStacktrace) {
+ activeStacktrace = minifiedStacktrace;
+ }
const frames = useMemo(() => activeStacktrace.frames ?? [], [activeStacktrace.frames]);
const {projects} = useProjects();
const project = useMemo(
@@ -161,6 +171,10 @@ export function StackTraceProvider({
]
);
+ if (!stacktrace) {
+ return ;
+ }
+
return (
{children}
);
diff --git a/static/app/components/stackTrace/types.tsx b/static/app/components/stackTrace/types.tsx
index 7d0f5c0c63f3..173e4920e0d9 100644
--- a/static/app/components/stackTrace/types.tsx
+++ b/static/app/components/stackTrace/types.tsx
@@ -55,7 +55,7 @@ export type StackTraceMeta = {
export interface StackTraceProviderProps {
children: ReactNode;
event: Event;
- stacktrace: StacktraceType;
+ stacktrace: StacktraceType | null;
/** When true, all frames start collapsed regardless of their position. */
collapseAll?: boolean;
/** Optional exception index in the full exception values list. */