Skip to content

fix(completer): guard against index panic when job deleted during completion#1308

Merged
brandur merged 3 commits into
riverqueue:masterfrom
tsushanth:fix/completer-len-guard-deleted-job
Jul 16, 2026
Merged

fix(completer): guard against index panic when job deleted during completion#1308
brandur merged 3 commits into
riverqueue:masterfrom
tsushanth:fix/completer-len-guard-deleted-job

Conversation

@tsushanth

Copy link
Copy Markdown
Contributor

Problem

Both InlineCompleter.JobSetStateIfRunning (~line 96) and AsyncCompleter.JobSetStateIfRunning (~line 205) index jobs[0] unconditionally after calling pilot.JobSetStateIfRunningMany.

The river driver intentionally returns 0 rows when a job is deleted while the completer is finalizing it — this is the UnknownJobIgnored contract documented in the shared driver tests. When that happens, both completers panic with an index-out-of-range error instead of handling the case gracefully.

Fix

Add a len(jobs) == 0 guard before the jobs[0] access in both InlineCompleter and AsyncCompleter. When the driver signals that the job no longer exists (by returning an empty slice), the completer returns nil and silently skips emitting a subscribe event — matching the driver's documented intent.

Two new unit tests (TestInlineJobCompleter_CompleteDeletedJob and TestAsyncJobCompleter_CompleteDeletedJob) exercise this path using the existing partialExecutorMock infrastructure, confirming no panic occurs.

Closes #1303

Comment thread internal/jobcompleter/job_completer.go Outdated
// The driver intentionally returns 0 rows when a job is deleted while the
// completer is finalizing it (see UnknownJobIgnored shared driver test).
// Guard against an index-out-of-range panic in that case.
if len(jobs) == 0 {

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.

Just as a minor stylistic nit, can you change these to if len(jobs) < 1?

@tsushanth

Copy link
Copy Markdown
Contributor Author

Done — changed to len(jobs) < 1 in both guard sites.

@brandur

brandur commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

Thanks!

Actually, two more small things:

@brandur
brandur merged commit 3b7efa5 into riverqueue:master Jul 16, 2026
12 checks passed
brandur added a commit that referenced this pull request Jul 17, 2026
…#1312)

This one's a follow up to #1308 which modifies the completers to handle
a rare condition where no rows are returned from `JobSetStateIfRunningMany`.
Codex caught it while I was looking at the other PR.

Here, also modify `JobSetStateIfRunningMany` in the SQLite driver so
that if a job is missing from query return, in omits the element
completely instead of adding a `nil` element in the return slice,
bringing its behavior in line with Postgres. We add a check in the
driver test suite to verify the consistent behavior.
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.

Completer can panic if completion races with job deletion

2 participants