{"record":{"id":"30ad8d1164aba5be","repo":"BerriAI/litellm","slug":"logging-obj-is-required-30ad8d","errorCode":null,"errorMessage":"logging_obj is required","messagePattern":"logging_obj is required","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"litellm/files/main.py","lineNumber":164,"sourceCode":"    custom_llm_provider: FileCreateProvider | None = None,\n    extra_headers: dict[str, str] | None = None,\n    extra_body: dict[str, str] | None = None,\n    **kwargs,\n) -> OpenAIFileObject | Coroutine[Any, Any, OpenAIFileObject]:\n    \"\"\"\n    Files are used to upload documents that can be used with features like Assistants, Fine-tuning, and Batch API.\n\n    LiteLLM Equivalent of POST: POST https://api.openai.com/v1/files\n\n    Specify either provider_list or custom_llm_provider.\n    \"\"\"\n    try:\n        _is_async: Final = kwargs.pop(\"acreate_file\", False) is True\n        optional_params: Final = GenericLiteLLMParams(**kwargs)\n        litellm_params_dict: Final = dict(**kwargs)\n        logging_obj: Final = cast(LiteLLMLoggingObj | None, kwargs.get(\"litellm_logging_obj\"))\n        if logging_obj is None:\n            raise ValueError(\"logging_obj is required\")\n        client: Final = kwargs.get(\"client\")\n\n        ### TIMEOUT LOGIC ###\n        timeout = optional_params.timeout or kwargs.get(\"request_timeout\", 600) or 600\n        # set timeout for 10 minutes by default\n\n        if (\n            timeout is not None\n            and isinstance(timeout, httpx.Timeout)\n            and supports_httpx_timeout(cast(str, custom_llm_provider)) is False\n        ):\n            read_timeout: Final = timeout.read or 600\n            timeout = read_timeout  # default 10 min timeout\n        elif timeout is not None and not isinstance(timeout, httpx.Timeout):\n            timeout = float(timeout)\n        elif timeout is None:\n            timeout = 600.0\n","sourceCodeStart":146,"sourceCodeEnd":182,"githubUrl":"https://github.com/BerriAI/litellm/blob/6c2dcb801bf2b75c18f1bb24140e7cf57465cc4d/litellm/files/main.py#L146-L182","documentation":"litellm.create_file requires an initialized LiteLLM logging object passed in kwargs as litellm_logging_obj. It is normally injected by LiteLLM's router/main layer before the function runs; if it is absent (None), the function refuses to proceed because success/failure logging and cost tracking could not work.","triggerScenarios":"Calling litellm.files.main.create_file (or the internal acreate_file path) directly instead of through the public litellm.create_file API, so kwargs never contain litellm_logging_obj; or a custom fork/wrapper that strips kwargs before delegating.","commonSituations":"Users importing internal modules to bypass the public API; mocking tests that call create_file with hand-built kwargs; upgrades that changed the internal kwarg plumbing while code called private entry points.","solutions":["Call the public API: litellm.create_file(file=..., purpose='fine-tune'|'batch'|'assistants', custom_llm_provider='openai') — it sets up logging for you","If you must call create_file directly, pass a logging object: from litellm.litellm_core_utils.litellm_logging import Logging; kwargs['litellm_logging_obj'] = Logging(model, stream=False, call_type='apass_through_endpoint')","Check that nothing in your wrapper pops or filters litellm_logging_obj out of kwargs before the call"],"exampleFix":"# before\nfrom litellm.files.main import create_file\nresp = create_file(file=open('f.jsonl','rb'), purpose='batch', custom_llm_provider='openai')\n\n# after\nimport litellm\nresp = litellm.create_file(file=open('f.jsonl','rb'), purpose='batch', custom_llm_provider='openai')","handlingStrategy":"validation","validationCode":"kwargs.setdefault(\"litellm_logging_obj\", None)\nif kwargs[\"litellm_logging_obj\"] is None and \"litellm_logging_obj\" not in kwargs:\n    # call public API instead; it injects the logger\n    import litellm  # use litellm.create_file(...)","typeGuard":"def has_logging_obj(kwargs: dict) -> bool:\n    lo = kwargs.get(\"litellm_logging_obj\")\n    return lo is not None and hasattr(lo, \"update_from_kwargs\")","tryCatchPattern":null,"preventionTips":["Never import litellm.files.main.create_file directly; use litellm.create_file","In wrappers, forward **kwargs untouched"],"tags":["files-api","logging","internal-api-misuse"],"backgroundTag":null,"analyzedSha":"6c2dcb801bf2b75c18f1bb24140e7cf57465cc4d","analyzedAt":"2026-08-15T07:12:03.035Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}