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/statistic.py:183 in the daily/period statistic endpoint. `parse_time_range` is called with `account.timezone` (asserted non-None just above) and the request's `start`/`end`. ValueError becomes 400; the SQL parameters (`tz`, `app_id`, `invoke_from`) are only appended to `arg_dict` after a successful parse.

Source

Thrown at api/controllers/console/app/statistic.py:183

        sql_query = f"""SELECT
    {converted_created_at} AS date,
    COUNT(*) AS message_count
FROM
    messages
WHERE
    app_id = :app_id
    AND invoke_from != :invoke_from"""
        assert account.timezone is not None
        arg_dict: dict[str, object] = {
            "tz": account.timezone,
            "app_id": app_model.id,
            "invoke_from": InvokeFrom.DEBUGGER,
        }

        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:
            sql_query += " AND created_at >= :start"
            arg_dict["start"] = start_datetime_utc

        if end_datetime_utc:
            sql_query += " AND created_at < :end"
            arg_dict["end"] = end_datetime_utc

        sql_query += " GROUP BY date ORDER BY date"

        response_data = []

        with db.engine.begin() as conn:
            rs = conn.execute(sa.text(sql_query), arg_dict)
            for i in rs:
                response_data.append({"date": str(i.date), "message_count": i.message_count})

View on GitHub (pinned to ef8544b173)

Solutions

  1. Format `start`/`end` as `YYYY-MM-DD HH:MM`.
  2. Set `account.timezone` to a valid IANA zone.
  3. Ensure `start <= end`.

Example fix

// before
GET /apps/<id>/statistics/day-conversations?start=2024-01-01
// after
GET /apps/<id>/statistics/day-conversations?start=2024-01-01%2000:00&end=2024-02-01%2000:00
Defensive patterns

Strategy: validation

Validate before calling

import datetime, pytz
TIME_FMT = "%Y-%m-%d %H:%M"
pytz.timezone(account.timezone)
if req_data.start: datetime.datetime.strptime(req_data.start, TIME_FMT)
if req_data.end:   datetime.datetime.strptime(req_data.end, TIME_FMT)
if req_data.start and req_data.end:
    assert datetime.datetime.strptime(req_data.start, TIME_FMT) <= 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 valid_stat_range(s, e) -> bool:
    return all(v is None or (_RE.match(v) and _ok(v)) for v in (s, e))
def _ok(v):
    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}/statistics/day-conversations", params=p)
except HTTPError as err:
    if err.response.status_code == 400:
        raise ValueError(f"bad statistics range: {err.response.text}") from err
    raise

Prevention

When it happens

Trigger: The app statistics endpoint receives `start`/`end` that do not match `YYYY-MM-DD HH:MM`, reference an unknown timezone, or define a reversed range (start > end).

Common situations: Dashboard requests an analytics window using a localized ISO string, or the user account's timezone is misconfigured to a non-IANA value.

Related errors


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