Azure / Azure/azure-sdk-for-python

[BUG] create_finetuning_job() crashes with UnboundLocalError when validation_data is None (optional per signature)

Open
#45,770 6 comments 0 reactions 3 assignees Claimed by @saanikaguptamicrosoft View on GitHub
customer-reported Machine Learning needs-team-attention question Service Attention
Dominant language
Python
Stars
5.6k
Forks
3.4k
Avg merge
1d 21h
Merged PRs (30d)
193

Description

## Bug Report

**Package:** `azure-ai-ml`
**Version:** `1.32.0` (latest as of March 18, 2026)
**Python:** `3.14.2`
**OS:** macOS 15.3

---

### Describe the bug

`create_finetuning_job()` crashes with `UnboundLocalError` when `validation_data` is omitted, despite the function signature correctly declaring it as `Optional[str] = None`.

The root cause is in `azure/ai/ml/finetuning/_create_job.py` line 71: `validation_data_input` is only assigned inside an `if validation_data:` block (lines 53–56) but is then passed **unconditionally** to `CustomModelFineTuningJob` on line 71.

Notably, a pylint suppression comment on that exact line — `# pylint: disable=(possibly-used-before-assignment` — shows the linter caught this but it was suppressed rather than fixed (commit `7af4a4d`, Jan 16 2025).

The bug affects **all fine-tuning job classes** — the identical pattern exists in:
- `CustomModelFineTuningJob`
- `AzureOpenAIFineTuningJob`
- `VertexAIFineTuningJob`

---

### To Reproduce

```python
from azure.ai.ml.finetuning import create_finetuning_job, FineTuningTaskType

# validation_data omitted — it is Optional per the signature, this should be valid
create_finetuning_job(
task=FineTuningTaskType.CHAT_COMPLETION,
training_data="azureml:my-train:1",
model="azureml://registries/azureml-mistral/models/Mistral-large-2407/versions/1",
output_model_name_prefix="my-model",
)
```

### Actual result

```
UnboundLocalError: cannot access local variable 'validation_data_input'
where it is not associated with a value
```

### Expected result

Job object is returned with `validation_data=None`. No error raised.

---

### Root cause

```python
# _create_job.py lines 53–71
if validation_data:
validation_data_input = Input( # only assigned when truthy
type=AssetTypes.URI_FILE,
path=validation_data,
)

custom_model_finetuning_job = CustomModelFineTuningJob(
...
validation_data=validation_data_input, # pylint: disable=(possibly-used-before-assignment
# ↑ UnboundLocalError when validation_data=None
)
```

---

### Suggested fix (one line per affected class)

```python
# Change:
validation_data=validation_data_input,

# To:
validation_data=validation_data_input if validation_data else None,
```

---

### Workaround

```python
# Pass training_data as fallback when no eval split exists
create_finetuning_job(
...
validation_data=eval_asset_id or train_asset_id,
)
```

---

### Signature proof (shows validation_data is correctly Optional but body doesn't honour it)

```
$ python -c "
import inspect
from azure.ai.ml.finetuning import create_finetuning_job
sig = inspect.signature(create_finetuning_job)
for name, param in sig.parameters.items():
required = param.default is inspect.Parameter.empty
print(f'{name:35s} required={required} default={repr(param.default)}')
"

model required=True default=
task required=True default=
training_data required=True default=
output_model_name_prefix required=True default=
validation_data required=False default=None ← Optional but crashes when None
hyperparameters required=False default=None
compute required=False default=None
instance_types required=False default=None
job_tier required=False default=None
```

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.