Filtering VLANGroup by vid_ranges.contains in GraphQL fails with “cannot cast type integer to int4range” #11687

Closed
opened 2025-12-29 21:48:37 +01:00 by adam · 3 comments
Owner

Originally created by @pheus on GitHub (Oct 4, 2025).

Originally assigned to: @pheus on GitHub.

NetBox Edition

NetBox Community

NetBox Version

v4.4.2

Python Version

3.12

Steps to Reproduce

Filtering vlan_group_list by a scalar VLAN ID using the vid_ranges.contains GraphQL filter returns an error instead of matching groups whose VID ranges include the value.

  1. Ensure a VLANGroup exists with vid_ranges that include VLAN 10 (e.g., [1,11)).
  2. Run the GraphQL query below against /graphql/.
  3. The request fails with the error shown instead of returning the matching VLANGroup.
query MyQuery {
  vlan_group_list(filters: { vid_ranges: { contains: 10 } }) {
    id
    name
    vid_ranges
  }
}

Expected Behavior

The query should succeed and return all VLANGroup records whose vid_ranges include the given VLAN ID (e.g., 10), without errors.
If no groups match, the API should return an empty list. The response should include the requested fields for each matching group.

Observed Behavior

{
  "data": null,
  "errors": [
    {
      "message": "cannot cast type integer to int4range\nLINE 1: ... WHERE \"ipam_vlangroup\".\"vid_ranges\" @> (ARRAY[10])::int4...\n                                                             ^",
      "path": ["vlan_group_list"]
    }
  ]
}

Server traceback (excerpt)

django.db.utils.ProgrammingError: cannot cast type integer to int4range
LINE 1: ... "ipam_vlangroup"."vid_ranges" @> (ARRAY[10])::int4...
                                                             ^
Originally created by @pheus on GitHub (Oct 4, 2025). Originally assigned to: @pheus on GitHub. ### NetBox Edition NetBox Community ### NetBox Version v4.4.2 ### Python Version 3.12 ### Steps to Reproduce Filtering `vlan_group_list` by a scalar VLAN ID using the `vid_ranges.contains` GraphQL filter returns an error instead of matching groups whose VID ranges include the value. 1. Ensure a `VLANGroup` exists with `vid_ranges` that include VLAN 10 (e.g., `[1,11)`). 2. Run the GraphQL query below against `/graphql/`. 3. The request fails with the error shown instead of returning the matching `VLANGroup`. ```graphql query MyQuery { vlan_group_list(filters: { vid_ranges: { contains: 10 } }) { id name vid_ranges } } ``` ### Expected Behavior The query should succeed and return all `VLANGroup` records whose `vid_ranges` include the given VLAN ID (e.g., `10`), without errors. If no groups match, the API should return an empty list. The response should include the requested fields for each matching group. ### Observed Behavior ```json { "data": null, "errors": [ { "message": "cannot cast type integer to int4range\nLINE 1: ... WHERE \"ipam_vlangroup\".\"vid_ranges\" @> (ARRAY[10])::int4...\n ^", "path": ["vlan_group_list"] } ] } ``` *Server traceback* (excerpt) ```text django.db.utils.ProgrammingError: cannot cast type integer to int4range LINE 1: ... "ipam_vlangroup"."vid_ranges" @> (ARRAY[10])::int4... ^ ```
adam added the type: bugstatus: acceptedseverity: low labels 2025-12-29 21:48:37 +01:00
adam closed this issue 2025-12-29 21:48:37 +01:00
Author
Owner

@pheus commented on GitHub (Oct 4, 2025):

Cause

  • VLANGroup.vid_ranges is an array of ranges (int4range[]), not an array of integers.
  • The GraphQL filter treats it as if it were an array of ints, so it generates an array‑contains check: vid_ranges @> ARRAY[10].
  • PostgreSQL then attempts to coerce 10 to an int4range (or int4range[]) to satisfy @>, which fails with:
    cannot cast type integer to int4range.
  • The intended semantics are range‑contains‑value on each element of the array (i.e., “does any stored range include 10?”), not “array contains 10”.
@pheus commented on GitHub (Oct 4, 2025): #### Cause - `VLANGroup.vid_ranges` is an **array of ranges** (`int4range[]`), not an array of integers. - The GraphQL filter treats it **as if it were an array of ints**, so it generates an **array‑contains** check: `vid_ranges @> ARRAY[10]`. - PostgreSQL then attempts to coerce `10` to an `int4range` (or `int4range[]`) to satisfy `@>`, which fails with: `cannot cast type integer to int4range`. - The intended semantics are **range‑contains‑value** on **each element** of the array (i.e., “does **any** stored range include 10?”), not “array contains 10”.
Author
Owner

@pheus commented on GitHub (Oct 4, 2025):

I think a small, reusable change can address this:

  • Add a generic ORM lookup any_range_contains for ArrayField(RangeField) that matches rows where a scalar value is contained by any range in the array.
  • Reuse it in IPAM by wiring VLANGroup’s FilterSet (contains_vid) to this lookup, removing the current raw‑SQL/custom helper.
  • For GraphQL, keep the public API friendly (vid_ranges: { contains: 10 }) and map it internally to __any_range_contains via a custom filter input/method (no schema churn).

If that sounds reasonable, I’m happy to open a draft PR with the lookup + FilterSet wiring and tests for the ORM and FilterSet.

@pheus commented on GitHub (Oct 4, 2025): I think a small, reusable change can address this: - Add a generic ORM lookup **`any_range_contains`** for `ArrayField(RangeField)` that matches rows where a scalar value is contained by **any** range in the array. - Reuse it in IPAM by wiring `VLANGroup`’s FilterSet (`contains_vid`) to this lookup, removing the current raw‑SQL/custom helper. - For GraphQL, keep the public API friendly (`vid_ranges: { contains: 10 }`) and map it internally to `__any_range_contains` via a custom filter input/method (no schema churn). If that sounds reasonable, I’m happy to open a draft PR with the lookup + FilterSet wiring and tests for the ORM and FilterSet.
Author
Owner

@jnovinger commented on GitHub (Oct 6, 2025):

Thanks, @pheus . Sounds like a reasonable approach.

@jnovinger commented on GitHub (Oct 6, 2025): Thanks, @pheus . Sounds like a reasonable approach.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/netbox#11687