From 13510b18aa85ffbf60aa3dc12a7a351c42c2fd12 Mon Sep 17 00:00:00 2001 From: Marlies Mayerhofer <74332854+marliessophie@users.noreply.github.com> Date: Mon, 13 Jul 2026 11:57:48 +0200 Subject: [PATCH 1/2] fix(experiments): preserve run metadata precedence --- langfuse/_client/client.py | 6 ++--- tests/unit/test_propagate_attributes.py | 34 +++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 4 deletions(-) diff --git a/langfuse/_client/client.py b/langfuse/_client/client.py index 6ce72d27a..98155d760 100644 --- a/langfuse/_client/client.py +++ b/langfuse/_client/client.py @@ -2877,9 +2877,10 @@ async def _process_experiment_item( ) final_observation_metadata = { + **(item_metadata or {}), + **(experiment_metadata or {}), "experiment_name": experiment_name, "experiment_run_name": experiment_run_name, - **(experiment_metadata or {}), } trace_id = span.trace_id @@ -2920,9 +2921,6 @@ async def _process_experiment_item( {"dataset_id": dataset_id, "dataset_item_id": dataset_item_id} ) - if isinstance(item_metadata, dict): - final_observation_metadata.update(item_metadata) - experiment_id = dataset_run_id or fallback_experiment_id experiment_item_id = ( dataset_item_id or get_sha256_hash_hex(_serialize(input_data))[:16] diff --git a/tests/unit/test_propagate_attributes.py b/tests/unit/test_propagate_attributes.py index 0ef92ac10..faa992878 100644 --- a/tests/unit/test_propagate_attributes.py +++ b/tests/unit/test_propagate_attributes.py @@ -2748,6 +2748,40 @@ def test_experiment_id_is_stable_across_local_items( assert len(experiment_ids) == 1 assert result.experiment_id == next(iter(experiment_ids)) + def test_experiment_run_metadata_overrides_item_metadata( + self, langfuse_client, memory_exporter + ): + langfuse_client.run_experiment( + name="Metadata precedence", + run_name="run-name", + data=[ + { + "input": "test", + "metadata": {"shared": "item", "item_only": "yes"}, + } + ], + task=lambda *, item, **kwargs: "result", + metadata={"shared": "run"}, + ) + langfuse_client.flush() + + span = self.get_span_by_name(memory_exporter, "experiment-item-run") + self.verify_span_attribute( + span, + f"{LangfuseOtelSpanAttributes.OBSERVATION_METADATA}.shared", + "run", + ) + self.verify_span_attribute( + span, + f"{LangfuseOtelSpanAttributes.OBSERVATION_METADATA}.experiment_run_name", + "run-name", + ) + self.verify_span_attribute( + span, + f"{LangfuseOtelSpanAttributes.OBSERVATION_METADATA}.item_only", + "yes", + ) + def test_experiment_attributes_propagate_with_dataset( self, langfuse_client, memory_exporter, monkeypatch ): From 1cf26ee23d136585b74fc9fdafa6b104edcf5c2d Mon Sep 17 00:00:00 2001 From: Marlies Mayerhofer <74332854+marliessophie@users.noreply.github.com> Date: Mon, 13 Jul 2026 13:25:45 +0200 Subject: [PATCH 2/2] fix(experiments): preserve metadata type guard --- langfuse/_client/client.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/langfuse/_client/client.py b/langfuse/_client/client.py index 98155d760..e03e79f40 100644 --- a/langfuse/_client/client.py +++ b/langfuse/_client/client.py @@ -2877,7 +2877,7 @@ async def _process_experiment_item( ) final_observation_metadata = { - **(item_metadata or {}), + **(item_metadata if isinstance(item_metadata, dict) else {}), **(experiment_metadata or {}), "experiment_name": experiment_name, "experiment_run_name": experiment_run_name,