{"record":{"id":"579b12cac330def4","repo":"langgenius/dify","slug":"str-e-579b12","errorCode":null,"errorMessage":"{str(e)}","messagePattern":"\\{str\\(e\\)\\}","errorType":"http","errorClass":null,"httpStatus":400,"severity":"error","filePath":"api/controllers/console/app/workflow_statistic.py","lineNumber":116,"sourceCode":"        200,\n        \"Daily runs statistics retrieved successfully\",\n        console_ns.models[WorkflowDailyRunsStatisticResponse.__name__],\n    )\n    @setup_required\n    @login_required\n    @account_initialization_required\n    @with_current_user\n    @rbac_permission_required(RBACResourceScope.APP, RBACPermission.APP_MONITOR)\n    @get_app_model\n    @model_validate(WorkflowStatisticQuery)\n    def get(self, req_data: WorkflowStatisticQuery, account: Account, app_model: App):\n\n        assert account.timezone is not None\n\n        try:\n            start_date, end_date = parse_time_range(req_data.start, req_data.end, account.timezone)\n        except ValueError as e:\n            abort(400, description=str(e))\n\n        response_data = self._workflow_run_repo.get_daily_runs_statistics(\n            tenant_id=app_model.tenant_id,\n            app_id=app_model.id,\n            triggered_from=WorkflowRunTriggeredFrom.APP_RUN,\n            start_date=start_date,\n            end_date=end_date,\n            timezone=account.timezone,\n        )\n\n        return jsonify({\"data\": response_data})\n\n\n@console_ns.route(\"/apps/<uuid:app_id>/workflow/statistics/daily-terminals\")\nclass WorkflowDailyTerminalsStatistic(Resource):\n    def __init__(self, *args, **kwargs):\n        super().__init__(*args, **kwargs)\n        session_maker = sessionmaker(bind=db.engine, expire_on_commit=False)","sourceCodeStart":98,"sourceCodeEnd":134,"githubUrl":"https://github.com/langgenius/dify/blob/ef8544b173fd6cd7a8e71df2cab576e52bebbfbc/api/controllers/console/app/workflow_statistic.py#L98-L134","documentation":"HTTP 400 returned by the daily workflow runs statistics endpoint (GET /apps/<app>/workflow/runs/daily). The handler wraps `libs.datetime_utils.parse_time_range` in a try/except ValueError and re-emits the exception text via `abort(400, description=str(e))`. `parse_time_range` raises ValueError for malformed time strings (expected `YYYY-MM-DD HH:MM`), unparseable timezones, or when `start > end`.","triggerScenarios":"Calling GET /console/api/apps/<app_id>/workflow/runs/daily?start=...&end=... with a start/end value that fails `datetime.strptime(value, \"%Y-%m-%d %H:%M\")`, or with `start` later than `end`. The account timezone comes from `account.timezone` and must be a valid pytz zone; an unknown zone raises from `pytz.timezone(tzname)`.","commonSituations":"Frontend sending ISO 8601 (`2024-01-01T00:00:00Z`) or date-only strings instead of `YYYY-MM-DD HH:MM`; date picker returning end-before-start ranges; account record with a null/invalid `timezone` (the `assert account.timezone is not None` just above would actually trip first as an AssertionError, but a non-None invalid tz hits this path).","solutions":["Format both `start` and `end` query params as `YYYY-MM-DD HH:MM` (e.g. `2024-08-12 09:30`) in the client before sending.","Validate client-side that `start <= end` before issuing the request.","Confirm the authenticated account has a valid IANA timezone string in `account.timezone` (set in account profile/settings).","If you need ISO 8601 / date-only input, normalize to `YYYY-MM-DD HH:MM` at the API boundary rather than relying on the default format."],"exampleFix":"// before\nfetch(`/apps/${appId}/workflow/runs/daily?start=2024-08-01T00:00:00Z&end=2024-08-12`)\n// after\nconst fmt = (d: Date) => d.toISOString().slice(0,16).replace('T',' ')\nfetch(`/apps/${appId}/workflow/runs/daily?start=${fmt(start)}&end=${fmt(end)}`)","handlingStrategy":"validation","validationCode":"import datetime, pytz\n\ndef valid_range(start: str | None, end: str | None, tzname: str) -> bool:\n    fmt = \"%Y-%m-%d %H:%M\"\n    s = datetime.datetime.strptime(start, fmt) if start else None\n    e = datetime.datetime.strptime(end, fmt) if end else None\n    pytz.timezone(tzname)  # raises if invalid\n    return not (s and e and s > e)\n\n# call before GET /apps/<id>/workflow/runs/daily\nif not valid_range(req.start, req.end, account.timezone):\n    raise ValueError(\"bad range\")","typeGuard":"from typing import Optional\nimport re\n\nDATE_RE = re.compile(r\"^\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}$\")\n\ndef is_workflow_stat_time(v: Optional[str]) -> bool:\n    return v is None or bool(DATE_RE.match(v))","tryCatchPattern":"try:\n    resp = client.get(f\"/apps/{app}/workflow/runs/daily\", params={\"start\": s, \"end\": e})\nexcept HTTPError as err:\n    if err.response.status_code == 400:\n        # parse_time_range failed: fix format/order and retry once\n        ...\n    raise","preventionTips":["Always format workflow-statistic dates as YYYY-MM-DD HH:MM in the client.","Validate start <= end before sending.","Centralize date formatting in one shared client util across all four statistic tabs.","Ensure account.timezone is set to a valid IANA zone."],"tags":["validation","datetime","workflow-statistics","http-400"],"backgroundTag":null,"analyzedSha":"ef8544b173fd6cd7a8e71df2cab576e52bebbfbc","analyzedAt":"2026-08-12T05:15:17.394Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}