BerriAI/litellm · error · ValueError

Invalid value passed in for async_delete_assistants. Only bo

Error message

Invalid value passed in for async_delete_assistants. Only bool or None allowed

What it means

Raised by litellm.assistants.delete_assistant when the 'async_delete_assistants' kwarg is neither bool nor None. It is the same internal sync/async routing flag pattern used across the assistants API, validated right after GenericLiteLLMParams and get_litellm_params are built.

Source

Thrown at litellm/assistants/main.py:425

        )


def delete_assistant(
    custom_llm_provider: Literal["openai", "azure"],
    assistant_id: str,
    client: Any | None = None,
    api_key: str | None = None,
    api_base: str | None = None,
    api_version: str | None = None,
    **kwargs,
) -> AssistantDeleted | Coroutine[Any, Any, AssistantDeleted]:
    optional_params: Final = GenericLiteLLMParams(api_key=api_key, api_base=api_base, api_version=api_version, **kwargs)

    litellm_params_dict: Final = get_litellm_params(**kwargs)

    async_delete_assistants: Final[bool | None] = kwargs.pop("async_delete_assistants", None)
    if async_delete_assistants is not None and not isinstance(async_delete_assistants, bool):
        raise ValueError("Invalid value passed in for async_delete_assistants. Only bool or None allowed")

    ### TIMEOUT LOGIC ###
    timeout = optional_params.timeout or kwargs.get("request_timeout", 600) or 600
    # set timeout for 10 minutes by default

    if (
        timeout is not None
        and isinstance(timeout, httpx.Timeout)
        and supports_httpx_timeout(custom_llm_provider) is False
    ):
        read_timeout: Final = timeout.read or 600
        timeout = read_timeout  # default 10 min timeout
    elif timeout is not None and not isinstance(timeout, httpx.Timeout):
        timeout = float(timeout)
    elif timeout is None:
        timeout = 600.0

    response: AssistantDeleted | Coroutine[Any, Any, AssistantDeleted] | None = None

View on GitHub (pinned to 6c2dcb801b)

Solutions

  1. Pass async_delete_assistants as a bool or drop it: litellm.delete_assistant(..., async_delete_assistants=True).
  2. For async, call await litellm.adelete_assistant(...) directly.
  3. Sanitize kwargs built from user input before forwarding to LiteLLM.

Example fix

# before
litellm.delete_assistant("asst_abc", async_delete_assistants="true")

# after
await litellm.adelete_assistant("asst_abc")
# or: litellm.delete_assistant("asst_abc", async_delete_assistants=True)
Defensive patterns

Strategy: type-guard

Validate before calling

if "async_delete_assistants" in kwargs and not isinstance(kwargs["async_delete_assistants"], (bool, type(None))):
    kwargs.pop("async_delete_assistants")  # let LiteLLM pick the default path

Type guard

def is_valid_assistants_flag(v) -> bool:
    return v is None or isinstance(v, bool)

Prevention

When it happens

Trigger: Calling litellm.delete_assistant(...) with async_delete_assistants set to a non-bool such as 'false', 0-as-string, or a list. The isinstance check only accepts bool or None.

Common situations: String flags from environment/config plumbing; users trying to force async behavior with a string instead of using adelete_assistant; copy-pasted snippets across the assistants API where flag names differ subtly.

Related errors


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