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
- Format `start`/`end` as `YYYY-MM-DD HH:MM`.
- Set `account.timezone` to a valid IANA zone.
- 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
- Centralize the `YYYY-MM-DD HH:MM` formatting in a shared analytics client.
- Surface invalid timezone errors at profile-save time, not at query time.
- Ensure the dashboard cannot send start > end by clamping the picker.
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.