langgenius/dify · warning

{str(e)}

Error message

{str(e)}

What it means

Flask `abort(400, description=str(e))` (HTTP 400) at api/controllers/console/app/conversation.py:136 in the conversation list handler. `parse_time_range(req_data.start, req_data.end, account.timezone)` raises ValueError for malformed `YYYY-MM-DD HH:MM` inputs, an invalid `account.timezone`, or start > end. The handler asserts `account.timezone is not None` immediately before, so a None timezone would surface as an AssertionError (500), not this 400.

Source

Thrown at api/controllers/console/app/conversation.py:136

        if req_data.keyword:
            from libs.helper import escape_like_pattern

            escaped_keyword = escape_like_pattern(req_data.keyword)
            query = query.join(Message, Message.conversation_id == Conversation.id).where(
                or_(
                    Message.query.ilike(f"%{escaped_keyword}%", escape="\\"),
                    Message.answer.ilike(f"%{escaped_keyword}%", escape="\\"),
                )
            )

        account = current_user
        assert account.timezone is not None

        try:
            start_datetime_utc, end_datetime_utc = parse_time_range(req_data.start, req_data.end, account.timezone)
        except ValueError as e:
            abort(400, description=str(e))

        if start_datetime_utc:
            query = query.where(Conversation.created_at >= start_datetime_utc)

        if end_datetime_utc:
            end_datetime_utc = end_datetime_utc.replace(second=59)
            query = query.where(Conversation.created_at < end_datetime_utc)

        # FIXME, the type ignore in this file
        if req_data.annotation_status == "annotated":
            query = (
                query.options(selectinload(Conversation.message_annotations))  # type: ignore[arg-type]
                .join(  # type: ignore
                    MessageAnnotation, MessageAnnotation.conversation_id == Conversation.id
                )
                .group_by(Conversation.id)
            )
        elif req_data.annotation_status == "not_annotated":

View on GitHub (pinned to ef8544b173)

Solutions

  1. Format both `start` and `end` as `YYYY-MM-DD HH:MM` (URL-encode the space).
  2. Ensure `account.timezone` is a valid IANA zone (e.g. 'America/New_York') before calling.
  3. Guarantee `start <= end`.

Example fix

// before
GET /apps/<id>/conversations?start=2024-01-01T00:00:00Z
// after
GET /apps/<id>/conversations?start=2024-01-01%2000:00
Defensive patterns

Strategy: validation

Validate before calling

import datetime, pytz
TIME_FMT = "%Y-%m-%d %H:%M"
pytz.timezone(account.timezone)  # fails fast on bad tz
if req_data.start: datetime.datetime.strptime(req_data.start, TIME_FMT)
if req_data.end:   datetime.datetime.strptime(req_data.end, TIME_FMT)

Type guard

import datetime, re
_RE = re.compile(r"^\d{4}-\d{2}-\d{2} \d{2}:\d{2}$")
def is_valid_range_str(v: str | None) -> bool:
    if not v:
        return True
    if not _RE.match(v):
        return False
    try:
        datetime.datetime.strptime(v, "%Y-%m-%d %H:%M")
        return True
    except ValueError:
        return False

Try / catch

try:
    resp = client.get(f"/console/api/apps/{app_id}/conversations", params=p)
except HTTPError as err:
    if err.response.status_code == 400:
        raise ValueError(f"bad time range: {err.response.text}") from err
    raise

Prevention

When it happens

Trigger: Calling the conversation list API with `start`/`end` query params that fail `parse_time_range`, e.g. wrong datetime format, an unknown IANA timezone on the user account, or a start that is later than end.

Common situations: Frontend sends an ISO timestamp (`2024-01-01T00:00:00Z`) instead of the expected `YYYY-MM-DD HH:MM`, or the user's account timezone is set to a name pytz cannot resolve.

Related errors


AI-assisted analysis of langgenius/dify@ef8544b173 (2026-08-12). Data as JSON: /api/errors/12273b0bb739f1f0. Report an issue: GitHub.