From c02a1bae9d4d902945644bedd7d19698b51f7527 Mon Sep 17 00:00:00 2001 From: Will Date: Fri, 10 Jul 2026 15:40:06 +0100 Subject: [PATCH 1/2] fix(fine_tuning): copy hyperparameters dict before Azure-specific mutation create_fine_tuning_job() did `hyperparameters = hyperparameters or {}`, which keeps a reference to the caller's dict when a non-empty one is passed in. The Azure branch then pops prompt_loss_weight from that same object, silently mutating the caller's dict as a side effect Copy into a new dict before any provider-specific mutation, and add a regression test that mocks the Azure handler and asserts the caller's hyperparameters dict still contains prompt_loss_weight after the call returns --- litellm/fine_tuning/main.py | 2 +- tests/batches_tests/test_fine_tuning_api.py | 40 +++++++++++++++++++++ 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/litellm/fine_tuning/main.py b/litellm/fine_tuning/main.py index ce5074cdaf5..736ef6969bc 100644 --- a/litellm/fine_tuning/main.py +++ b/litellm/fine_tuning/main.py @@ -174,7 +174,7 @@ def create_fine_tuning_job( optional_params = GenericLiteLLMParams(**kwargs) # handle hyperparameters - hyperparameters = hyperparameters or {} # original hyperparameters + hyperparameters = dict(hyperparameters or {}) # original hyperparameters # For Azure, extract Azure-specific hyperparameters before creating OpenAI-spec hyperparameters azure_specific_hyperparams = {} diff --git a/tests/batches_tests/test_fine_tuning_api.py b/tests/batches_tests/test_fine_tuning_api.py index c489685eaff..4e77e4737b8 100644 --- a/tests/batches_tests/test_fine_tuning_api.py +++ b/tests/batches_tests/test_fine_tuning_api.py @@ -622,3 +622,43 @@ async def test_mock_azure_create_fine_tune_job_with_azure_specific_params(): # Verify the response assert response.id == "ft-azure-123" assert response.model == "gpt-4.1-mini-2025-04-14" + + +def test_create_fine_tuning_job_does_not_mutate_caller_hyperparameters(): + from openai.types.fine_tuning.fine_tuning_job import ( + Hyperparameters as OAIHyperparameters, + ) + from litellm.types.utils import LiteLLMFineTuningJob + + mock_response = LiteLLMFineTuningJob( + id="ft-azure-456", + model="gpt-4.1-mini-2025-04-14", + created_at=1677610602, + status="validating_files", + fine_tuned_model=None, + object="fine_tuning.job", + hyperparameters=OAIHyperparameters(n_epochs=2), + organization_id="org-123", + seed=42, + training_file="file-123", + result_files=[], + ) + + params = {"n_epochs": 2, "prompt_loss_weight": 0.25} + + with patch( + "litellm.llms.azure.fine_tuning.handler.AzureOpenAIFineTuningAPI.create_fine_tuning_job", + return_value=mock_response, + ): + create_fine_tuning_job( + model="gpt-4.1-mini-2025-04-14", + training_file="file-123", + hyperparameters=params, + custom_llm_provider="azure", + api_base="https://test.openai.azure.com", + api_key="test-key", + api_version="2025-04-01-preview", + ) + + assert "prompt_loss_weight" in params + assert params["prompt_loss_weight"] == 0.25 From 720b2c04faa3607802e9c1cdc356438464b98554 Mon Sep 17 00:00:00 2001 From: Will Date: Fri, 10 Jul 2026 19:56:26 +0100 Subject: [PATCH 2/2] fix(fine_tuning): correct stale comment on hyperparameters copy --- litellm/fine_tuning/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/litellm/fine_tuning/main.py b/litellm/fine_tuning/main.py index 736ef6969bc..ef0703b091e 100644 --- a/litellm/fine_tuning/main.py +++ b/litellm/fine_tuning/main.py @@ -174,7 +174,7 @@ def create_fine_tuning_job( optional_params = GenericLiteLLMParams(**kwargs) # handle hyperparameters - hyperparameters = dict(hyperparameters or {}) # original hyperparameters + hyperparameters = dict(hyperparameters or {}) # shallow copy; callers' dict is not mutated # For Azure, extract Azure-specific hyperparameters before creating OpenAI-spec hyperparameters azure_specific_hyperparams = {}