Skip to content

fix(tasks): distinguish a failed Trigger lookup from an empty schedule - #806

Open
sweetmantech wants to merge 1 commit into
mainfrom
fix/enrich-tasks-lookup-failure
Open

fix(tasks): distinguish a failed Trigger lookup from an empty schedule#806
sweetmantech wants to merge 1 commit into
mainfrom
fix/enrich-tasks-lookup-failure

Conversation

@sweetmantech

@sweetmantech sweetmantech commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

Implements docs#284 and closes the enrichment false-negative row of chat#1918.

Merge order: docs#284 first, then this.

The bug

enrichTasks.ts had four paths returning the identical shape { recent_runs: [], upcoming: [], timezone: null }:

path meaning
no trigger_schedule_id nothing to look up
fetchTriggerRuns / retrieveScheduleTimezone threw lookup failed
retrieveTaskRun payload threw lookup partly failed
live schedule, no runs yet genuinely empty

A consumer cannot tell a failure from an empty result. Observed live 2026-07-29: two tasks reported upcoming: [] while GET api.trigger.dev/api/v1/schedules/{id} showed both schedules active, with a correct cron and nextRun. 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: boolean on EnrichedTask, set true only when the lookup errored:

  • no trigger_schedule_idfalse (there was nothing to look up, and an empty result is correct)
  • lookup succeeded, even with zero runs → false
  • lookup threw → true

Additive 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):

test asserts
flags trigger_lookup_failed when the Trigger lookup throws the failure path
does NOT flag a live schedule that legitimately has no runs yet the distinction that was missing
does NOT flag a task that has no trigger_schedule_id no false alarm for unscheduled tasks

The 4 pre-existing toEqual assertions were updated to carry the new field — including the existing "when Trigger.dev fails" case, which now asserts trigger_lookup_failed: true and so doubles as a regression guard.

  • pnpm exec vitest run lib/tasks16 files, 79 tests, all pass
  • pnpm exec eslint on both touched files → clean
  • pnpm exec tsc --noEmit → no errors in either file

Remaining 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_failed to EnrichedTask so consumers can detect lookup errors.

  • Bug Fixes
    • enrichTasks sets trigger_lookup_failed: true only when the Trigger lookup throws; returns false for no trigger_schedule_id and for live schedules with no runs.
    • Updated tests cover the error path and both non-error cases; all pass.

Written for commit f7d7530. Summary will update on new commits.

Review in cubic

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
@vercel

vercel Bot commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
api Ready Ready Preview Jul 31, 2026 12:46am

Request Review

@cursor

cursor Bot commented Jul 31, 2026

Copy link
Copy Markdown

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.

@coderabbitai

coderabbitai Bot commented Jul 31, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@sweetmantech, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 37 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

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 configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 0ab9a732-3efc-463b-bd4d-807a877759c3

📥 Commits

Reviewing files that changed from the base of the PR and between f38823c and f7d7530.

⛔ Files ignored due to path filters (1)
  • lib/tasks/__tests__/enrichTasks.test.ts is excluded by !**/*.test.*, !**/__tests__/** and included by lib/**
📒 Files selected for processing (1)
  • lib/tasks/enrichTasks.ts

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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, so upcoming can be empty while trigger_lookup_failed stays false; this can hide real lookup errors and lead downstream logic/UI to trust incomplete task state—propagate lookup failures into trigger_lookup_failed (or stop treating upcoming as 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
Loading

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread lib/tasks/enrichTasks.ts
recent_runs: recentRuns,
upcoming,
timezone: timezone ?? null,
trigger_lookup_failed: false,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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>

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant