Skip to content

Python 3.14: UnboundLocalError in compute_metadata when repo_info is provided #8

@setuc

Description

@setuc

Bug Report

SDK version: braintrust 0.5.6
Python version: 3.14.2
Platform: macOS (darwin aarch64)

Description

When using braintrust.init() with repo_info and git_metadata_settings=GitMetadataSettings(collect="none"), the SDK crashes with UnboundLocalError: cannot access local variable 'merged_git_metadata_settings' during lazy experiment ID resolution.

This is a Python 3.14 scoping change as Python 3.14 enforces stricter scoping for variables defined only inside one branch of an if/else block.

Reproduction

import braintrust
from braintrust.git_fields import RepoInfo

braintrust.login(api_key="<key>", force_login=True)

repo_info = RepoInfo(commit="abc123", branch="main", dirty=False, author_name="test")

exp = braintrust.init(
    project="my_project",
    experiment="test_experiment",
    repo_info=repo_info,
    git_metadata_settings=braintrust.GitMetadataSettings(collect="none"),
)

exp.log(input={"test": "hello"}, output="world", scores={"accuracy": 1.0})
exp.flush()  # Crashes here

Error

File "braintrust/logger.py", line 1659, in compute_metadata
    elif merged_git_metadata_settings and merged_git_metadata_settings.collect != "none":
         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
UnboundLocalError: cannot access local variable 'merged_git_metadata_settings' where it is not associated with a value

Root Cause

In logger.py around line 1642-1660, merged_git_metadata_settings is only assigned inside the else branch:

if repo_info:                                   # line 1642
    repo_info_arg = repo_info                   # line 1643 — skips assignment
else:
    merged_git_metadata_settings = state.git_metadata_settings  # line 1645 — only here
    ...

# Later:
elif merged_git_metadata_settings and ...:      # line 1659 — BOOM: variable never assigned

When repo_info is truthy (which it always is when you pass it), the else block never executes, so merged_git_metadata_settings is never assigned. Python 3.14 raises UnboundLocalError because the variable is referenced in a branch that's unreachable given the control flow.

Fix

Add merged_git_metadata_settings = None before the if/else block:

merged_git_metadata_settings = None  # Ensure variable exists in all code paths
if repo_info:
    repo_info_arg = repo_info
else:
    merged_git_metadata_settings = state.git_metadata_settings
    ...

Workaround

We patched the SDK source directly:

sed -i '' 's/        if repo_info:/        merged_git_metadata_settings = None\n        if repo_info:/' .venv/lib/python3.14/site-packages/braintrust/logger.py

Impact

This blocks all experiment logging on Python 3.14. Project logging (traces) works fine — only experiments are affected because they use the lazy compute_metadata path.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions