Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion static/app/views/detectors/components/detectorLink.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,11 @@ function UptimeDetectorDetails({detector}: {detector: UptimeDetector}) {
}

function CronDetectorDetails({detector}: {detector: CronDetector}) {
const config = detector.dataSources[0].queryObj.config;
const config = detector.dataSources[0]?.queryObj?.config;

if (!config) {
return null;
}

return <DetailItem>{scheduleAsText(config)}</DetailItem>;
}
Expand Down
11 changes: 6 additions & 5 deletions static/app/views/detectors/list/cron.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -52,15 +52,16 @@ import {selectCheckInData} from 'sentry/views/insights/crons/utils/selectCheckIn
import {useMonitorStats} from 'sentry/views/insights/crons/utils/useMonitorStats';

function VisualizationCell({detector}: {detector: CronDetector}) {
const cronId = detector.dataSources[0].queryObj.id;
const cronEnvironments = detector.dataSources[0].queryObj.environments;
const queryObj = detector.dataSources[0]?.queryObj;
const cronId = queryObj?.id;
const cronEnvironments = queryObj?.environments;

const elementRef = useRef<HTMLDivElement>(null);
const {width: containerWidth} = useDimensions({elementRef});
const timelineWidth = useDebouncedValue(containerWidth, 1000);
const timeWindowConfig = useTimeWindowConfig({timelineWidth});
const {data: monitorStats, isPending} = useMonitorStats({
monitors: [detector.dataSources[0].queryObj.id],
monitors: cronId ? [cronId] : [],
timeWindowConfig,
});

Expand All @@ -72,7 +73,7 @@ function VisualizationCell({detector}: {detector: CronDetector}) {
height="100%"
>
<Stack gap="sm" width="100%" ref={elementRef}>
{cronEnvironments.map(environment => {
{cronEnvironments?.map(environment => {
if (isPending) {
return <CheckInPlaceholder key={environment.name} />;
}
Expand Down Expand Up @@ -108,7 +109,7 @@ const ADDITIONAL_COLUMNS: MonitorListAdditionalColumn[] = [
return (
<SimpleTable.RowCell data-column-name="environment-label" alignSelf="start">
<Stack gap="sm" width="100%">
{detector.dataSources[0].queryObj.environments.map(environment => {
{detector.dataSources[0]?.queryObj?.environments.map(environment => {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unsafe map on environments

High Severity

When queryObj is null, optional chaining yields undefined for environments, but .map is still invoked on that value. That throws the same class of runtime error this PR targets, so the environment column can still crash for cron detectors without a queryObj.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit c6ddf6d. Configure here.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: Incomplete optional chaining on environments will cause a crash when queryObj is null. The .map() function will be called on an undefined value, throwing a TypeError.
Severity: HIGH

Suggested Fix

Add optional chaining before the .map() call to safely handle cases where environments is undefined. The line should be changed to {detector.dataSources[0]?.queryObj?.environments?.map(environment => { ... });}.

Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent. Verify if this is a real issue. If it is, propose a fix; if not, explain why it's
not valid.

Location: static/app/views/detectors/list/cron.tsx#L112

Potential issue: In the environment column renderer, the code accesses
`detector.dataSources[0]?.queryObj?.environments.map(...)`. While optional chaining is
used for `queryObj`, it is not used before the `.map()` call. The pull request's context
confirms that `queryObj` can be `null` at runtime. In such cases,
`detector.dataSources[0]?.queryObj?.environments` evaluates to `undefined`. Attempting
to call `.map()` on `undefined` will result in a `TypeError: Cannot read properties of
undefined (reading 'map')`, causing a crash in the UI component when rendering the
environment column for a detector with a null `queryObj`.

Did we get this right? 👍 / 👎 to inform future reviews.

return (
<Text density="compressed" key={environment.name}>
<MonitorEnvironmentLabel
Expand Down
Loading