fix(tasks): distinguish a failed Trigger lookup from an empty schedule - #806
fix(tasks): distinguish a failed Trigger lookup from an empty schedule#806sweetmantech wants to merge 1 commit into
Conversation
enrichTasks had four paths that all returned {recent_runs: [], upcoming: [],
timezone: null}: no schedule id, the runs/timezone lookup threw, the payload
retrieval threw, and a live schedule with no runs yet. Consumers could not tell
a failure from a genuinely empty result.
Observed 2026-07-29: two tasks reported upcoming: [] while the Trigger API
showed both schedules active with a correct cron and nextRun. The false
negative was read as a dead schedule and a duplicate task was created.
Adds trigger_lookup_failed, true only when the lookup errored. A task with no
trigger_schedule_id is false — there was nothing to look up.
Implements docs#284.
chat#1918
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Bugbot is not enabled for your account, so this pull request was not reviewed. Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs. |
|
Warning Review limit reached
Next review available in: 37 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Plus Run ID: ⛔ Files ignored due to path filters (1)
📒 Files selected for processing (1)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
1 issue found across 2 files
Confidence score: 3/5
- In
lib/tasks/enrichTasks.ts, the latest-run lookup failure path is misclassified as success, soupcomingcan be empty whiletrigger_lookup_failedstays false; this can hide real lookup errors and lead downstream logic/UI to trust incomplete task state—propagate lookup failures intotrigger_lookup_failed(or stop treatingupcomingas authoritative when lookup fails).
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="lib/tasks/enrichTasks.ts">
<violation number="1" location="lib/tasks/enrichTasks.ts:82">
P1: A failed latest-run lookup is still reported as successful, leaving `upcoming` empty with `trigger_lookup_failed: false`. Propagate that failure into this flag (or avoid treating `upcoming` as authoritative), otherwise consumers can again classify a live schedule as dead when payload retrieval is unavailable.</violation>
</file>
Architecture diagram
sequenceDiagram
participant UI as Client
participant API as GET /api/tasks
participant ET as enrichTasks()
participant DB as Database
participant TR as Trigger.dev API
Note over UI,TR: Task Enrichment Flow
UI->>API: GET /api/tasks
API->>ET: enrichTasks(tasks)
ET->>ET: For each task, check trigger_schedule_id
alt No trigger_schedule_id
ET->>ET: Return { recent_runs: [], upcoming: [], timezone: null, trigger_lookup_failed: false }
else Has trigger_schedule_id
ET->>TR: fetchTriggerRuns(scheduleId)
ET->>TR: retrieveScheduleTimezone(scheduleId)
alt Lookup succeeds
TR-->>ET: Trigger runs + timezone data
ET->>DB: selectAccountEmails()
DB-->>ET: Owner emails
ET->>ET: Return { recent_runs, upcoming, timezone, trigger_lookup_failed: false }
else Lookup throws
TR-->>ET: Error (network, 503, etc.)
ET->>ET: Return { recent_runs: [], upcoming: [], timezone: null, trigger_lookup_failed: true }
end
end
ET-->>API: EnrichedTask[] with trigger_lookup_failed flag
API-->>UI: JSON response
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
| recent_runs: recentRuns, | ||
| upcoming, | ||
| timezone: timezone ?? null, | ||
| trigger_lookup_failed: false, |
There was a problem hiding this comment.
P1: A failed latest-run lookup is still reported as successful, leaving upcoming empty with trigger_lookup_failed: false. Propagate that failure into this flag (or avoid treating upcoming as authoritative), otherwise consumers can again classify a live schedule as dead when payload retrieval is unavailable.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At lib/tasks/enrichTasks.ts, line 82:
<comment>A failed latest-run lookup is still reported as successful, leaving `upcoming` empty with `trigger_lookup_failed: false`. Propagate that failure into this flag (or avoid treating `upcoming` as authoritative), otherwise consumers can again classify a live schedule as dead when payload retrieval is unavailable.</comment>
<file context>
@@ -64,11 +75,19 @@ export async function enrichTasks(tasks: ScheduledAction[]): Promise<EnrichedTas
+ recent_runs: recentRuns,
+ upcoming,
+ timezone: timezone ?? null,
+ trigger_lookup_failed: false,
+ },
] as const;
</file context>
Implements docs#284 and closes the enrichment false-negative row of chat#1918.
Merge order: docs#284 first, then this.
The bug
enrichTasks.tshad four paths returning the identical shape{ recent_runs: [], upcoming: [], timezone: null }:trigger_schedule_idfetchTriggerRuns/retrieveScheduleTimezonethrewretrieveTaskRunpayload threwA consumer cannot tell a failure from an empty result. Observed live 2026-07-29: two tasks reported
upcoming: []whileGET api.trigger.dev/api/v1/schedules/{id}showed both schedules active, with a correct cron andnextRun. Another account enriched fine in the same window, so it was transient. The false negative was read as "this schedule is dead" and a duplicate task was created — a double-email risk on a customer account.The fix
trigger_lookup_failed: booleanonEnrichedTask, set true only when the lookup errored:trigger_schedule_id→false(there was nothing to look up, and an empty result is correct)falsetrueAdditive and non-breaking; consumers that ignore it behave exactly as before.
Tests
RED→GREEN, 3 new tests, all confirmed RED (
expected undefined to be true/false):trigger_lookup_failedwhen the Trigger lookup throwstrigger_schedule_idThe 4 pre-existing
toEqualassertions were updated to carry the new field — including the existing "when Trigger.dev fails" case, which now assertstrigger_lookup_failed: trueand so doubles as a regression guard.pnpm exec vitest run lib/tasks→ 16 files, 79 tests, all passpnpm exec eslinton both touched files → cleanpnpm exec tsc --noEmit→ no errors in either fileRemaining verification
The flag needs exercising against a preview with a real Trigger outage (or a forced one) to confirm it surfaces end-to-end through
GET /api/tasks. Unit tests cover the branch logic, not the live response.🤖 Generated with Claude Code
Summary by cubic
Distinguishes a failed Trigger.dev lookup from a genuinely empty schedule in task enrichment to prevent false negatives and duplicate tasks. Adds
trigger_lookup_failedtoEnrichedTaskso consumers can detect lookup errors.enrichTaskssetstrigger_lookup_failed: trueonly when the Trigger lookup throws; returnsfalsefor notrigger_schedule_idand for live schedules with no runs.Written for commit f7d7530. Summary will update on new commits.