BerriAI/litellm · error · ValueError

`pages` must be integers, not booleans

Error message

`pages` must be integers, not booleans

What it means

Raised when the `pages` parameter passed to Azure Document Intelligence OCR is a list containing a boolean. Python bools are subclasses of int, so [True, 2] would otherwise silently become '2,3' (True→1-based 2); LiteLLM explicitly rejects booleans to prevent that silent corruption. It fires before any network call, during request transformation.

Source

Thrown at litellm/llms/azure_ai/ocr/document_intelligence/transformation.py:155

          - list[str]: tokens like "1" or "3-5". Validated, joined as-is
            (treated as Azure-native, i.e. 1-based).
          - str: already in Azure format. Validated and whitespace-stripped.
        """
        pages_pattern: Final = re.compile(r"^\s*\d+(-\d+)?(\s*,\s*\d+(-\d+)?)*\s*$")

        if isinstance(pages, str):
            if not pages_pattern.match(pages):
                raise ValueError(
                    f"Invalid `pages` string for Azure Document Intelligence: "
                    f"{pages!r}. Expected format like '1-3,5,7-9'."
                )
            return pages.replace(" ", "")

        if isinstance(pages, list):
            if len(pages) == 0:
                return ""
            if any(isinstance(p, bool) for p in pages):
                raise ValueError("`pages` must be integers, not booleans")
            if all(isinstance(p, int) for p in pages):
                if any(p < 0 for p in pages):
                    raise ValueError("`pages` integers must be >= 0 (Mistral 0-based indices)")
                # Mistral 0-based -> Azure 1-based.
                return ",".join(str(p + 1) for p in sorted(set(pages)))
            if all(isinstance(p, str) for p in pages):
                joined: Final = ",".join(p.strip() for p in pages)
                if not pages_pattern.match(joined):
                    raise ValueError(
                        f"Invalid `pages` list for Azure Document Intelligence: "
                        f"{pages!r}. Expected tokens like '1' or '3-5'."
                    )
                return joined

        raise ValueError("`pages` must be a list[int] (0-based, Mistral-style) or a string like '1-3,5,7-9'.")

    @staticmethod
    def _normalize_features_param(features: object) -> str:

View on GitHub (pinned to 6c2dcb801b)

Solutions

  1. Pass only real integers in the list: [0, 1, 2] (0-based Mistral-style, converted to 1-based automatically).
  2. Filter/convert booleans before the call if they come from untyped input.
  3. Alternatively pass a validated string like '1-3,5'.

Example fix

# before
pages = [0, 1, True]  # bool leaked in from a config flag
litellm.aocr_document(model="azure_ai/doc-intelligence/prebuilt-layout", document=doc, pages=pages)

# after
pages = [p for p in pages if isinstance(p, int) and not isinstance(p, bool)]
litellm.aocr_document(model="azure_ai/doc-intelligence/prebuilt-layout", document=doc, pages=pages)
Defensive patterns

Strategy: type-guard

Validate before calling

def clean_pages(pages: list) -> list[int]:
    return [p for p in pages if isinstance(p, int) and not isinstance(p, bool)]

Type guard

def is_int_pages_list(v: object) -> bool:
    return isinstance(v, list) and all(isinstance(p, int) and not isinstance(p, bool) for p in v)

Prevention

When it happens

Trigger: Calling the azure_ai doc-intelligence OCR endpoint with optional_params={"pages": [True, False]} or [1, True] — any list where isinstance(p, bool) is True for at least one element.

Common situations: Building the pages list from flags/checkboxes or JSON where true/false leaked into an integer list; data deserialization (e.g. pydantic with loose typing, JSON 'true') inserting booleans.

Related errors


AI-assisted analysis of BerriAI/litellm@6c2dcb801b (2026-08-15). Data as JSON: /api/errors/8c22f880aabe1cf0. Report an issue: GitHub.