Repository navigation
fix(client): point the dataset-run helpers at the v4 read path in docs and logs - #1912
Conversation
…s and logs
Fixes langfuse-python#1906.
A Langfuse v4 deployment rejects the legacy dataset-run read endpoints with
404, so `get_dataset_run()`, `get_dataset_runs()` and `delete_dataset_run()`
cannot work there. Two things made that worse than merely inconvenient.
The docstrings said nothing about v4, and the raised error's `str()` starts
with the response headers, so the only signal a caller got was a bare 404
whose explanation sits in `exc.body`.
The error handlers were also dead code. All three were written as
`except Error as e:`, and `Error` here is the fern-generated
`langfuse.api.Error` -- a *subclass* of `langfuse.api.core.api_error.ApiError`.
The errors the SDK actually raises (`NotFoundError` and the rest of the
exported set) are `ApiError` subclasses that are not `Error`, so the clause
never fired and `handle_fern_exception` was never called either:
>>> issubclass(NotFoundError, ApiError)
True
>>> issubclass(NotFoundError, Error)
False
This change:
- adds a v4 note to each docstring naming the replacement read path, notes
that the `dataset_run_id` from `run_experiment()` is the same value those
return, and links the migration guide. `from_start_time` is called out as
required, since a literal follower otherwise gets a TypeError;
- makes the three clauses catch `ApiError`;
- routes all three failures through one `_handle_dataset_run_error()`, which
emits the v4 guidance and otherwise leaves the exception alone.
`handle_fern_exception` and `generate_error_message_fern` now take `ApiError`
instead of the narrower `Error`. Widening a parameter is safe for every
existing caller, `generate_error_message_fern` already dispatched on
`isinstance(..., ApiError)`, and leaving the annotations alone made mypy fail
with three `arg-type` errors on the newly reachable calls.
Two deliberate omissions in `_handle_dataset_run_error`:
- 404 is not routed to `handle_fern_exception`. Its 404 entry reads
"Internal error occurred. This is an unusual occurrence and we are monitoring
it closely" -- these helpers raise `NotFoundError` routinely, because asking
for a run that does not exist is an ordinary outcome, and a false claim at
ERROR level is also what error alerting keys on.
- a refused delete gets its own hint, not the read hint. There is no delete
counterpart on `client.api.experiments`, so telling a caller whose delete
was refused to "read the run" could lead them to conclude it was removed. It
was not.
Routing the helpers themselves onto the v4 read path is not part of this
change and is not a drop-in: `DatasetRunItem.id` has no experiment
counterpart, `dataset_name` needs a `datasets.list()` lookup, `metadata`
needs `fields=metadata`, `startTime`/`endTime` are clipped to the requested
`from_start_time` window, and pagination is cursor-based rather than
page-based. That mapping is a product decision.
Five other `except Error` clauses in this file share the latent bug --
`get_dataset`, `auth_check`, `create_dataset`, `create_dataset_item` and
`create_prompt` -- but they are left alone here: widening them changes
error-logging behaviour across unrelated methods.
Verified against a real v4 events_only deployment (langfuse 4.42.0): before,
all three helpers raised with no guidance and the error logger never ran;
after, the two read helpers log the read guidance, the delete helper logs the
delete-specific guidance, nothing is reported as an internal error, a
non-404 API error still reaches the original logger, and
`client.api.experiments.list(...)` returns ExperimentsResponse.
| ``client.api.experiments.list(from_start_time=...)`` and match on ``id`` | ||
| or ``name`` instead -- ``from_start_time`` is required, and | ||
| ``run_experiment()`` returns that same value as ``dataset_run_id``. See | ||
| https://langfuse.com/docs/v4. |
There was a problem hiding this comment.
Run name lacks dataset scope The old lookup uses both
dataset_name and run_name, but this guidance suggests matching an experiment by name alone. If two datasets use the same run name, that match is ambiguous and a caller could select the wrong run. Advise callers to include dataset_id when matching by name, or to use the run ID.
Knowledge Base Used: Dataset and run management
Prompt To Fix With AI
This is a comment left during a code review.
Path: langfuse/_client/client.py
Line: 2608-2611
Comment:
**Run name lacks dataset scope** The old lookup uses both `dataset_name` and `run_name`, but this guidance suggests matching an experiment by name alone. If two datasets use the same run name, that match is ambiguous and a caller could select the wrong run. Advise callers to include `dataset_id` when matching by name, or to use the run ID.
**Knowledge Base Used:** [Dataset and run management](https://app.greptile.com/personal-org-4986/-/custom-context/knowledge-base/langfuse/langfuse-python/-/docs/dataset-and-run-management.md)
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.greptile P2: the get_dataset_run docstring told callers to match experiments by id *or name*, but a bare name match is ambiguous when two datasets reuse a run name -- the old lookup this hint replaces keyed on both dataset_name and run_name. Name the dataset_id argument explicitly, say why name alone is not enough, and point at id as the reliable key. get_dataset_runs already passed dataset_id, so this aligns the two. Also fix two things CI would have caught in this same file: - _is_not_found passed a possibly-None status_code to int(), which mypy rejects; guard it before the try. - _handle_dataset_run_error's signature fits on one line, which is what ruff format wants. Verified: ruff check, ruff format --check, mypy langfuse all clean; tests/unit/test_dataset_run_v4_guidance.py + test_datasets.py 32 passed. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Good catch — fixed in 353c00c. The hint now names Two unrelated things CI caught in the same file while I was in there: |
fix(client): point the dataset-run helpers at the v4 read path in docs and logs
Fixes #1906.
What is wrong
On a Langfuse v4 deployment the three dataset-run read helpers cannot work: the
endpoints behind them are rejected with 404 in
events_onlymode. Two things madethat a bad experience rather than a merely inconvenient one.
The docstrings said nothing about v4. So the only signal a caller got was a
404 whose Python
str()begins with the response headers — the server's ownexplanation is only reachable through
exc.body.The error handlers were dead code. All three helpers were written as:
where
Errorislangfuse.api.Error, the fern-generated base class. The errorsthe SDK actually raises derive from
langfuse.api.core.api_error.ApiError:So the clause never fired for a server rejection, and
handle_fern_exception—which only logs — was never called either.
What this changes
Each of the three docstrings now states that the endpoint is unavailable on v4,
names
client.api.experiments.list()/list_items()as the replacement, notesthat the
dataset_run_idreturned byrun_experiment()is the same value thosereturn, and links the migration guide.
The three clauses now catch
ApiError, the type actually raised, instead of thefern base class that never matched.
All three delegate to
_handle_dataset_run_error(e), which decides once perfailure what to do: a recognized v4 rejection logs the actionable
WARNINGnaming the replacement, an ordinary 404 logs nothing, and every other status
continues through
handle_fern_exceptionas originally intended.delete_dataset_runpasses its own hint, because there is no delete counterpart on
client.api.experimentsand pointing the caller at the read path could lead themto conclude the run had been removed. The exception type is unchanged, so
anything already catching
NotFoundErrorkeeps working.Routing the helpers themselves onto the v4 read path is deliberately not part of
this change. It is not a drop-in:
DatasetRunItem.idhas no experiment counterpart,dataset_nameneeds adatasets.list()lookup,metadataneedsfields=metadata,startTime/endTimeare clipped to the requestedfrom_start_timewindow, andpagination is cursor-based instead of page-based. That mapping is a product decision
and belongs to a maintainer.
Scope note
client.pycontained eightexcept Errorclauses with this latent bug. Thethree dataset-run helpers are fixed here; the five left alone are
get_dataset,auth_check,create_dataset,create_dataset_itemandcreate_prompt. Wideningthem alters error-logging behaviour across unrelated methods, so it is left for a
separate decision.
404 is not routed through the error logger
handle_fern_exceptionmaps a bare status onto a generic message, and its 404 entryreads "Internal error occurred. This is an unusual occurrence and we are monitoring it
closely." These three helpers raise
NotFoundErrorroutinely — asking for a run thatdoes not exist is an ordinary outcome — so routing 404 through it would ship a false
claim at ERROR level, which is also what error alerting keys on. A v4 refusal and a 404
therefore log the actionable warning (or nothing), while every other status still goes
through
handle_fern_exceptionas originally intended.Verification
Against a real self-hosted Langfuse v4
events_onlydeployment (langfuse-web4.42.0) on base
0bc5897b:run_experiment()returns a populateddataset_run_idwithitem_count=2and adataset_run_url; the same client then fails to read that run back throughget_dataset_run()with the v4 404.get_dataset_run,get_dataset_runsanddelete_dataset_runall raisedNotFoundErrorwith no guidance reachable, and the error-log handler never ran.client.api.experiments.list(...)— thereplacement the guidance names — returns
ExperimentsResponseon the samedeployment.
New unit tests in
tests/unit/test_dataset_run_v4_guidance.py:ordinary 404, on missing bodies and on non-dict bodies;
client.api.experiments, so pointing the caller at the read path could lead them toconclude the run had been removed;
ApiError/Errorclass relationship that caused the dead handlers;a v4 refusal logs the guidance and never "Internal error", an ordinary 404 logs neither,
and a non-404 API error still reaches the original logger.
The
dataset_run_id== experimentidclaim was checked against the live deployment:the experiment returned by
experiments.list()carries the same id, and it resolves bothby
idand byname.The focused guidance suite recorded 25 passed during the initial implementation. The
correction at
353c00c4records 32 passed acrosstest_dataset_run_v4_guidance.pyandtest_datasets.py, withruff check,ruff format --checkandmypypassing. That correction scopes the migration hint to thedataset, guards a missing
status_codebefore the integer comparison, and formats thehelper signature.
client.pyhas 563 pre-existingrufffindings, identical before andafter this change.
These are historical local and contributor results. The current-head GitHub Actions runs
are
action_requiredwith no jobs executed; upstream CI has not yet run on this revision.The runtime change appears safe to merge, but the repository’s import-placement requirement must be satisfied first.
Summary
The PR adds v4 migration guidance to three legacy dataset-run helpers and catches generated API errors so a recognized v4 rejection produces an actionable warning. It also adds focused regression tests.
Reviews (1) · Last reviewed commit: "fix(client): point the dataset-run helpe..."