Skip to content

Bug: Multiple fields in in_fields configuration cause filter providers to malfunction #507

@SinoptikInc

Description

@SinoptikInc

Description

Description

When configuring multiple fields in the in_fields array within create_service_dependencies(), only the last field in the array generates working filter providers. All previous fields fail to create proper CollectionFilter instances due to a closure variable capture issue in the loop.

Environment

  • advanced-alchemy version: 1.4.5
  • Python version: 3.12
  • Framework: Litestar

Expected Behavior

All fields specified in in_fields should generate working filter providers that can be used via query parameters like fieldNameIn=value1,value2.

Actual Behavior

Only the last field in the in_fields array works correctly. Previous fields don't generate any CollectionFilter instances in the filters list, causing the filtering to be ignored.

Reproduction Steps

  1. Configure a controller with multiple fields in in_fields:
dependencies = providers.create_service_dependencies(
    MyService,
    "my_service",
    filters={
        "in_fields": [
            providers.FieldNameType("type", str),
            providers.FieldNameType("status", str),
        ],
    },
)
  1. Make a request with the first field filter: GET /api/endpoint?typeIn=value
  2. Observe that no CollectionFilter is generated for the type field
  3. Make a request with the last field filter: GET /api/endpoint?statusIn=value
  4. Observe that CollectionFilter works correctly for the status field

Root Cause Analysis

The issue is located in providers.py around lines 516-520:

for field_def in in_fields:
    field_def = FieldNameType(name=field_def, type_hint=str) if isinstance(field_def, str) else field_def

    def create_in_filter_provider(
        field_name: FieldNameType,
    ) -> Callable[..., Optional[CollectionFilter[field_def.type_hint]]]:  # ← Problem here

The closure captures the loop variable field_def by reference, not by value. When the loop completes, all created functions reference the last value of field_def, causing previous fields to malfunction.

Workaround

Currently using manual providers for additional fields:

def status_filter_provider(statusIn: list[str] | None = None) -> filters.CollectionFilter:
    return filters.CollectionFilter(field_name="status", values=statusIn)

dependencies = providers.create_service_dependencies(
    MyService,
    "my_service", 
    filters={
        "in_fields": [
            providers.FieldNameType("type", str),  # Only one field works
        ],
    },
) | {
    "status_filter": status_filter_provider,  # Manual workaround
}

Suggested Fix

The closure should capture the loop variable by value, for example by passing it as a default parameter:

def create_in_filter_provider(
    field_name: FieldNameType = field_def,  # Capture by value
) -> Callable[..., Optional[CollectionFilter]]:

Or restructure the function creation to avoid the closure issue entirely.

Additional Notes

  • The same issue likely affects not_in_fields configuration as well
  • Single field in in_fields works correctly
  • This is a classic Python closure gotcha that affects any loop creating functions with references to loop variables

URL to code causing the issue

No response

MCVE

# Your MCVE code here

Steps to reproduce

1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error

Screenshots

"In the format of: ![SCREENSHOT_DESCRIPTION](SCREENSHOT_LINK.png)"

Logs

Package Version

advanced-alchemy version: 1.4.5

Platform

  • Linux
  • Mac
  • Windows
  • Other (Please specify in the description above)

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions