BerriAI/litellm · error · ValueError

end_time is required, got={end_time} of type {type(end_time)

Error message

end_time is required, got={end_time} of type {type(end_time)}

What it means

Same normalization helper as start_time: end_time must be a datetime.datetime or a float. Any other type — None, int, string — raises this ValueError. The strictness exists because the helper converts timings to floats for span/log records; ints are notably not accepted by the isinstance(., float) check.

Source

Thrown at litellm/litellm_core_utils/litellm_logging.py:4727

            completion_start_time: Union[dt_object, float]

        Returns:
            Tuple[float, float, float]: A tuple containing the start time, end time, and completion start time as floats.
        """

        if isinstance(start_time, datetime.datetime):
            start_time_float = start_time.timestamp()
        elif isinstance(start_time, float):
            start_time_float = start_time
        else:
            raise ValueError(f"start_time is required, got={start_time} of type {type(start_time)}")

        if isinstance(end_time, datetime.datetime):
            end_time_float = end_time.timestamp()
        elif isinstance(end_time, float):
            end_time_float = end_time
        else:
            raise ValueError(f"end_time is required, got={end_time} of type {type(end_time)}")

        if isinstance(completion_start_time, datetime.datetime):
            completion_start_time_float = completion_start_time.timestamp()
        elif isinstance(completion_start_time, float):
            completion_start_time_float = completion_start_time
        else:
            completion_start_time_float = end_time_float

        return start_time_float, end_time_float, completion_start_time_float

    @staticmethod
    def append_system_prompt_messages(kwargs: dict | None = None, messages: Any | None = None):
        """
        Append system prompt messages to the messages
        """
        if kwargs is not None:
            if kwargs.get("system") is not None and isinstance(kwargs.get("system"), str):
                if messages is None:

View on GitHub (pinned to 6c2dcb801b)

Solutions

  1. Use datetime objects or explicitly cast to float: end_time=float(end_time)
  2. Guard None with a fallback before logging: end_time or datetime.datetime.now()
  3. In custom handlers, mirror LiteLLM's own pattern of always creating both timestamps at handler entry

Example fix

# before
end_time = int(time.time())  # ValueError: end_time is required

# after
end_time = float(time.time())
# or
end_time = datetime.datetime.now(datetime.timezone.utc)
Defensive patterns

Strategy: type-guard

Validate before calling

import datetime

def safe_end_time(t, fallback=None):
    if isinstance(t, datetime.datetime) or isinstance(t, float):
        return t
    return fallback if fallback is not None else datetime.datetime.now()

Type guard

import datetime

def is_valid_time_value(t) -> bool:
    return isinstance(t, datetime.datetime) or isinstance(t, float)

Prevention

When it happens

Trigger: Passing end_time as an int epoch (int(time.time())), None (unset on early failure paths), or a serialized string into Logging methods / custom callback handlers that reach this converter.

Common situations: Custom callbacks computing durations with integer arithmetic; JSON round-tripping turning datetimes into strings; failure handlers where end_time was never set before logging.

Related errors


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