{"record":{"id":"d771a951d06622fb","repo":"BerriAI/litellm","slug":"invalid-log-format-log-format-must-be-one-of","errorCode":null,"errorMessage":"Invalid log_format: {log_format}. Must be one of: 'json_array', 'ndjson', 'single'","messagePattern":"Invalid log_format: (.+?)\\. Must be one of: 'json_array', 'ndjson', 'single'","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"litellm/integrations/generic_api/generic_api_callback.py","lineNumber":176,"sourceCode":"                \"endpoint not set for GenericAPILogger, GENERIC_LOGGER_ENDPOINT not found in environment variables\"\n            )\n\n        self.headers: dict[str, str] = self._get_headers(headers)\n        self.endpoint: str = endpoint\n        self.event_types: list[API_EVENT_TYPES] | None = event_types\n        self.callback_name: str | None = callback_name\n        self.max_retries = max(0, int(max_retries or 0))\n        retry_delay_value: Final = 0.0 if retry_delay is None else retry_delay\n        self.retry_delay = max(0.0, float(retry_delay_value))\n        self.timeout = timeout\n\n        # Validate and store log_format\n        if log_format is not None and log_format not in [\n            \"json_array\",\n            \"ndjson\",\n            \"single\",\n        ]:\n            raise ValueError(f\"Invalid log_format: {log_format}. Must be one of: 'json_array', 'ndjson', 'single'\")\n        self.log_format: LOG_FORMAT_TYPES = log_format or \"json_array\"\n\n        verbose_logger.debug(\n            \"in init GenericAPILogger, callback_name: %s, endpoint %s, headers %s, event_types: %s, log_format: %s\",\n            self.callback_name,\n            self.endpoint,\n            self.headers,\n            self.event_types,\n            self.log_format,\n        )\n\n        #########################################################\n        # Init variables for batch flushing logs\n        #########################################################\n        self.flush_lock = asyncio.Lock()\n        super().__init__(**kwargs, flush_lock=self.flush_lock)\n        asyncio.create_task(self.periodic_flush())\n        self.log_queue: list[dict | StandardLoggingPayload] = []","sourceCodeStart":158,"sourceCodeEnd":194,"githubUrl":"https://github.com/BerriAI/litellm/blob/6c2dcb801bf2b75c18f1bb24140e7cf57465cc4d/litellm/integrations/generic_api/generic_api_callback.py#L158-L194","documentation":"Raised by GenericAPILogger.__init__ when the log_format argument (or the log_format loaded from a generic_api_compatible_callbacks.json config via callback_name) is not None and not one of the three supported formats: 'json_array', 'ndjson', 'single'. The value is validated at construction time, so the logger fails fast before any request is logged. If log_format is None the default 'json_array' is used.","triggerScenarios":"Constructing GenericAPILogger(callback_name=..., log_format='JSON') with wrong casing, passing log_format='json' or 'yaml', or defining a custom callback in generic_api_compatible_callbacks.json whose 'log_format' key contains a typo like 'ndjosn'. Also passing an empty string '' (which is not None, so it enters validation and fails).","commonSituations":"Users adding a generic API logging callback to litellm.callbacks and guessing the format name; teams loading callback config from their own JSON registry where a teammate edited the format value; copy-pasting config from examples written for a different library version that used different format names.","solutions":["Set log_format to exactly one of 'json_array', 'ndjson', or 'single' (case-sensitive), or omit it / pass None to get the 'json_array' default.","If using callback_name, open the callback config JSON (generic_api_compatible_callbacks.json) and fix the 'log_format' entry for that callback; the explicit argument must be None for the config value to take effect.","Add a startup assertion like assert log_format in (None, 'json_array', 'ndjson', 'single') before constructing the logger so misconfiguration is caught with a clearer message."],"exampleFix":"# before\nlogger = GenericAPILogger(endpoint=\"https://logs.example.com\", log_format=\"ndjson \")  # trailing space -> ValueError\n\n# after\nlogger = GenericAPILogger(endpoint=\"https://logs.example.com\", log_format=\"ndjson\")","handlingStrategy":"validation","validationCode":"from litellm.integrations.generic_api.generic_api_callback import GenericAPILogger\n\nVALID_LOG_FORMATS = {\"json_array\", \"ndjson\", \"single\"}\n\ndef make_logger(endpoint: str, log_format: str | None = None) -> GenericAPILogger:\n    if log_format is not None and log_format not in VALID_LOG_FORMATS:\n        raise ValueError(\n            f\"log_format must be one of {sorted(VALID_LOG_FORMATS)} or None, got {log_format!r}\"\n        )\n    return GenericAPILogger(endpoint=endpoint, log_format=log_format)","typeGuard":"def is_valid_log_format(value: object) -> bool:\n    return value is None or (isinstance(value, str) and value in {\"json_array\", \"ndjson\", \"single\"})","tryCatchPattern":null,"preventionTips":["Centralize the allowed log_format values in one constant shared by config parsing and logger construction.","Validate config files with a JSON schema that enums log_format before app startup.","Run a smoke-test at boot that constructs GenericAPILogger so format typos fail during deploy, not during traffic."],"tags":["config","validation","logging","constructor"],"backgroundTag":null,"analyzedSha":"6c2dcb801bf2b75c18f1bb24140e7cf57465cc4d","analyzedAt":"2026-08-15T07:12:03.035Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}