Skip to content

locals() usage causes failures when debugging due to namespace pollution #644

@bilelomrani1

Description

@bilelomrani1

While debugging a call inside the library, I discovered that the code constructing request parameters is using locals(). This breaks when stepping through the function in a debugger.

The relevant code:

all_args = locals()
all_args.pop("self")
all_args["model_id"] = all_args.pop("model")
kwargs = all_args.pop("kwargs")

if tools:
    all_args["tools"] = prepare_tools(tools, built_in_tools=self.BUILT_IN_TOOLS)

for i, message in enumerate(messages):
    if isinstance(message, ChatCompletionMessage):
        messages[i] = message.model_dump(
            exclude_none=True,
            exclude={"reasoning"},
        )
all_args["messages"] = messages

return await self._acompletion(CompletionParams(**all_args), **kwargs)

This works normally when executed without debugging. However, when stepping through the function in a debugger, the CompletionParams validation fails because all_args unexpectedly contains additional entries. Debuggers inject temporary variables into the local namespace for watch expressions, etc. When locals() is called during a debugging session, it captures these extra variables, which then get passed to CompletionParams(**all_args), causing a validation error.

I've reproduced this with both VSCode's debugger and pdb. This is expected debugger behavior, not a debugger bug, locals() returns the current local namespace, which debuggers necessarily modify to function.

Reproduction

  • Set a breakpoint in the AnyLLM.acompletion function.
  • Step through the code line by line
  • Observe that all_args contains debugger-injected variables
  • The call to CompletionParams(**all_args) fails with extra unexpected arguments
validated_self = self.__pydantic_validator__.validate_python(data, self_instance=self)
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
pydantic_core._pydantic_core.ValidationError: 6 validation errors for CompletionParams
self
  Extra inputs are not permitted [type=extra_forbidden, input_value=<any_llm.providers.mistra...r object at 0x10b3a8e30>, input_type=MistralProvider]
    For further information visit https://errors.pydantic.dev/2.12/v/extra_forbidden
model
  Extra inputs are not permitted [type=extra_forbidden, input_value='mistral-large-latest', input_type=str]
    For further information visit https://errors.pydantic.dev/2.12/v/extra_forbidden
kwargs
  Extra inputs are not permitted [type=extra_forbidden, input_value={}, input_type=dict]
    For further information visit https://errors.pydantic.dev/2.12/v/extra_forbidden
all_args
  Extra inputs are not permitted [type=extra_forbidden, input_value={'messages': [{'role': 'u...'m Bilel and I'm 28yo"}}, input_type=dict]
    For further information visit https://errors.pydantic.dev/2.12/v/extra_forbidden
i
  Extra inputs are not permitted [type=extra_forbidden, input_value=0, input_type=int]
    For further information visit https://errors.pydantic.dev/2.12/v/extra_forbidden
message
  Extra inputs are not permitted [type=extra_forbidden, input_value={'role': 'user', 'content...I'm Bilel and I'm 28yo"}, input_type=dict]
    For further information visit https://errors.pydantic.dev/2.12/v/extra_forbidden

Suggested fix

Don't use locals() and use explicit parameter capture instead. Happy to send a PR for this.

Metadata

Metadata

Assignees

No one assigned

    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