Annotation hit-history pager never ends for limit=0: has_more is computed from a page size the query does not use

已关闭
#42,322 1 条评论 1 个 reaction 已指派 0 人 在 GitHub 查看

还没有人认领这个 Issue。

评估

难度
3/5
预计耗时
1-2 天
新手友好度
68/100
Issue 类型
缺陷
描述清晰度
基本清楚
活跃度
活跃
技术栈
python
领域
api, backend

调研方向

从 GET /console/api/apps/{app_id}/annotations/{annotation_id}/hit-histories 的命中历史路由开始,检查它如何调用 libs/pagination.paginate_query。将 handler 的 page 和 limit 值与 pagination 实际使用的值进行比较,然后检查 AnnotationApi.get 和 AnnotationListApi.get 中相关的重新计算。完成标准是:无效的边界值不会导致无限的 has_more 响应,并且返回的 page 和 limit 与 query 匹配。

由索引模型根据 Issue 内容生成。

描述

Self Checks
  • I have searched for existing issues, and this has not been reported before
  • I am using the latest main
Dify version

main at a4d74f7c

Cloud or Self Hosted

Self Hosted (Source)

Steps to reproduce

GET /console/api/apps/{app_id}/annotations/{annotation_id}/hit-histories?limit=0

That route reads both pagination parameters straight off the query string with no bounds:

page = request.args.get("page", default=1, type=int)
limit = request.args.get("limit", default=20, type=int)
effective_limit = min(limit, 100)

min(limit, 100) has no lower bound, but libs/pagination.paginate_query floors both at 1 before it runs the query:

page = max(1, page)
per_page = max(1, per_page)

So the query is served with a page size of 1 while the response reports limit: 0, and has_more is computed from the requested value:

has_more=page * effective_limit < total

page * 0 < total is true for every page, so a client that walks pages until has_more is false never stops. Past the end it keeps receiving empty pages that still claim there is more. limit=-1 behaves the same way.

Driving the real paginate_query against a seven-row table, with the handler's own arithmetic:

--- client asks limit=0, walks pages until has_more is false ---
  page=1  rows=1 ids=[1] has_more=True   (paginate_query.has_next=True)
  ...
  page=7  rows=1 ids=[7] has_more=True   (paginate_query.has_next=False)
  page=8  rows=0 ids=[]  has_more=True   (paginate_query.has_next=False)
  page=9  rows=0 ids=[]  has_more=True
  page=10 rows=0 ids=[]  has_more=True
   -> client never stopped after 10 pages

--- the same walk with limit=3 ---
  page=3  rows=1 ids=[7] has_more=False -> client stops here

PaginatedResult.has_next is right in every one of those rows; it is the handler's separate recomputation from unclamped inputs that is not.

page has the same gap on this route: ?page=0 is served as page 1 while the response echoes page: 0.

The annotation list routes (AnnotationApi.get, service API AnnotationListApi.get) carry the same recomputation, introduced together with it in #41876. Those are currently protected because their query models declare limit: int = Field(default=20, ge=1), so only the hit-history route is reachable today.

✔️ Expected Behavior

has_more is false once the last page has been served, and limit/page in the response are the values the query actually used.

❌ Actual Behavior

has_more stays true forever for limit=0 or limit=-1, and the response reports a page size that was not used.

主要语言
TypeScript
星标
157k
派生
24.7k
平均合并
22 小时 32 分钟
30 天内合并 PR
611

贡献指南

打开贡献指南

从这里开始

  1. 先读完整个 Issue,再读项目的贡献指南。
  2. 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
  3. Fork 仓库,在一个分支上完成修改。
  4. 提交 Pull Request,并在描述里引用这个 Issue 编号。

langgenius/dify 的其他 Issue

查看 langgenius/dify 的全部 Issue

相似的 Issue

更多 TypeScript Issue

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。