Skip to content

fix(datasets): return early when deleteDatasetRuns matches no runs - #17788

Open
MoonlightAndSunlight wants to merge 2 commits into
langfuse:mainfrom
MoonlightAndSunlight:fix-dataset-runs-empty-selection
Open

MoonlightAndSunlight wants to merge 2 commits into
langfuse:mainfrom
MoonlightAndSunlight:fix-dataset-runs-empty-selection

Conversation

@MoonlightAndSunlight

@MoonlightAndSunlight MoonlightAndSunlight commented Sep 22, 2026

Copy link
Copy Markdown

What does this PR do?

deleteDatasetRuns falls back to datasetRuns[0].datasetId when filling in the queue payload,
but datasetId is optional in the input schema. If the caller omits it and none of the supplied
datasetRunIds match — the runs were already deleted, or they belong to another project —
findMany comes back empty, datasetRuns[0] is undefined, and reading .datasetId throws. The
request fails instead of reporting that there was nothing to delete.

The handler now returns as soon as the lookup comes back empty. Nothing is deleted, queued or
audited either way, so the early return only removes the crash; the response shape is unchanged.

Why return early instead of raising

The mutation is already idempotent in the other direction: it returns the runs it found, and its
audit entries — which are correct as written, since they are built from the findMany result rather
than from the input — simply do not exist when nothing matched. Turning "nothing matched" into a 404
would be a behaviour change beyond the crash this PR is fixing, so the existing contract is kept.

Type of change

  • Bug fix (non-breaking change which fixes an issue)

Mandatory Tasks

  • Make sure you have self-reviewed the code.

Checklist

Left empty on purpose: every bullet in the template is phrased as something that was not done, and
I removed the ones that did not apply.

No test added: nothing in the suite exercises deleteDatasetRuns, and pinning this would need a
seeded dataset run plus a tRPC caller. Happy to add one if you want it.

RetriggerConfidence Score: 4/5

The PR is not safe to merge until the empty-result guard preserves cleanup retries when datasetId is supplied.

Summary

This PR prevents deleteDatasetRuns from dereferencing an absent first result when no runs match. However, the new unconditional return also bypasses a valid asynchronous-cleanup retry path when the caller supplied a dataset ID.

  • Returns an empty run array for no-match requests.
  • Avoids the undefined datasetRuns[0] access.
  • Needs to preserve cleanup enqueueing when enough input is available after a partial deletion failure.

Reviews (1) · Last reviewed commit: "fix(datasets): return early when deleteD..."

@claude claude Bot left a comment

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.

Claude Code Review

This pull request is from a fork — automated review is disabled. A repository maintainer can comment @claude review to run a one-time review.

Comment on lines +2113 to +2115
if (datasetRuns.length === 0) {
return datasetRuns;
}

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.

P1 Cleanup retries are skipped

If PostgreSQL deletion succeeds but enqueueing the asynchronous ClickHouse cleanup fails, retrying this mutation finds no relational runs. This new return then exits before recreating the cleanup job, even when input.datasetId supplies the required dataset context, so the run's related data can remain undeleted. Limit the early return to cases where no dataset ID is available, or otherwise preserve cleanup retries.

Knowledge Base Used: Datasets and experiments

Prompt To Fix With AI
This is a comment left during a code review.
Path: web/src/features/datasets/server/dataset-router.ts
Line: 2113-2115

Comment:
**Cleanup retries are skipped**

If PostgreSQL deletion succeeds but enqueueing the asynchronous ClickHouse cleanup fails, retrying this mutation finds no relational runs. This new return then exits before recreating the cleanup job, even when `input.datasetId` supplies the required dataset context, so the run's related data can remain undeleted. Limit the early return to cases where no dataset ID is available, or otherwise preserve cleanup retries.

**Knowledge Base Used:** [Datasets and experiments](https://app.greptile.com/personal-org-4986/-/custom-context/knowledge-base/langfuse/langfuse/-/docs/datasets-and-experiments.md)

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

greptile pointed out that returning early on an empty result skips the async
cleanup enqueue. A retry after a committed delete whose enqueue failed would
then never re-enqueue, leaving the ClickHouse side undeleted. The early return
now only skips the enqueue when the caller gave no dataset id to enqueue with.
@MoonlightAndSunlight

Copy link
Copy Markdown
Author

Addressed in d4db147c6dbd.

Correct — returning early skipped the enqueue, so a retry after a committed delete whose enqueue
failed would leave the ClickHouse side undeleted for good. The early return now enqueues the cleanup
first when the caller supplied datasetId, and only returns without enqueueing when there is no
datasetId to enqueue with — which is exactly the case that would otherwise have crashed on
datasetRuns[0].

Re-enqueueing is safe: the queue handler deletes by run id.

This branch has not been deployed

No deployments
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