[BUG] Cloudflare KV binding 模式下 kvDriver.list() 沿用 EdgeOne 语义,字段名不匹配导致 key 格式下初始化 500 并耗尽 list 配额
Maintainers usually reply within 2 days
Assessment
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Newbie friendliness
- 64/100
- Issue type
- Bug
- Clarity
- Mostly clear
- Activity status
- Active
- Tech stack
- cloud, typescript
Research direction
Start in src/backend/internal/model/store/driver/kv.ts around lines 451-482, where the binding-mode list() reads item.key, page.complete and the cursor. Compare it with the Cloudflare semantics in the sibling cfkv.ts (name, list_complete, cursor). Done when the loop terminates on list_complete and returns the real key names. The issue's quota-design question about the key format is separate and should not be bundled into this fix.
Written by the indexing model from the issue text.
Description
请确认以下事项
- 我确认描述清晰有礼貌,已提供必要诊断信息,在最新版本上可以复现。
- 我确认已经查过相关文档和已有问题和讨论,本次反馈并非是重复提问。
- 我确认这是Worker项目问题,并非网络和操作导致,也不是Go版的问题。
- 我确认已阅读开源许可/免责条款/使用政策,理解使用的风险自行承担。
版本(必填)
main @ d3b79f8 (2026-10-11)
平台(必填)
Cloudflare Workers
DB_FORMAT(必填)
key(分 key)
DB_DRIVER(必填)
kv
存储驱动(必填)
无(问题发生在创建管理员的初始化阶段,尚未挂载任何存储)
问题描述(必填)
现象
在 Cloudflare Workers 上使用 KV binding + DB_FORMAT=key 时,初始化创建管理员必定失败:
/api/public/init/setup 返回 500 Internal Server Error(Hono 未捕获异常)。
仅把 DB_FORMAT 改为 map 后,同一请求返回 200 {"code":200,"message":"success"},初始化成功。
根因
src/backend/internal/model/store/driver/kv.ts 第 451-482 行,binding 模式的 list() 是按 EdgeOne KV 语义实现的(代码注释亦明确写了这点):
const page = await kv.list({ prefix, cursor, limit: 256 })
const pageKeys = Array.isArray(page?.keys) ? page.keys : []
for (const item of pageKeys) {
if (item?.key) keys.push(item.key) // ← EdgeOne: item.key
}
if (pageKeys.length > 0) {
cursor = pageKeys[pageKeys.length - 1].key || "" // ← 同样是 item.key
}
complete = Boolean(page?.complete) || pageKeys.length === 0 // ← EdgeOne: page.complete
而 Cloudflare Workers KV 的 KVNamespaceListResult 实际返回:
{ keys: { name: string; expiration?: number; metadata?: unknown }[];
list_complete: boolean; cursor?: string; cacheStatus: string | null }
两处字段名均不匹配:
item.key→ CF 为item.name,因此keys恒为空数组,list 事实上失效;page.complete→ CF 为page.list_complete,恒为undefined。
后果(两个叠加)
- 存储为空时:
pageKeys.length === 0使complete为 true,循环侥幸退出(但返回空数组,功能已失效)。 - 存储非空时:
complete恒为 false,且cursor被赋为undefined || ""即"",于是每一轮都用相同游标重复拉取同一页,while一路跑到guard < 1000上限 —— 单次list()调用就产生 1000 次真实 KV list 请求。
Cloudflare KV 免费版 list 配额为 1000 次/天(read 10 万/天、write 1000/天、delete 1000/天,每日 00:00 UTC 重置)。而 key 格式的 load() / save() 会对 6 张表逐表调用 list(),一次页面访问即可打满当天额度。额度耗尽后 list() 抛错 → saveDb() 抛异常 → Hono 返回裸 500。
附带问题
kvDriver.isAvailable() 只判断 binding 对象是否存在、不做真实读写探测,因此 /api/public/env_check 在存储实际不可写时仍返回「存储就绪」,严重误导排查(本次排查即因此多花大量时间)。
期望
- binding 模式改回 Cloudflare 语义(可参考同目录
cfkv.ts的实现); - 更关键的是配额设计层面:即使字段改对,
key格式「每次 load/save 对 6 张表调 list」在免费版 1000 次/天下仍不可持续(约 167 次访问/天即耗尽)。建议要么在文档中标注key + kv不适用于免费版,要么给 key 格式加一个索引键(用一次get换取 N 次list)。
报错信息(必填)
- 初始化接口:
POST /api/public/init/setup
→ HTTP 500
→ body: Internal Server Error
(无 code/message JSON,属 Hono 未捕获异常的裸 500)
- 环境检查接口(同一时刻,全部"就绪",与存储实际不可写矛盾):
GET /api/public/env_check
→ storage.available=true, error_code=null, db_load_error=null,
jwt.ready=true, resolved_driver=kv
- Cloudflare KV 命名空间控制台提示:
键-值条目无法列出。您在过去 24 小时内超出了计划所含的列出或读取配额。
- 切换为 map 后:
POST /api/public/init/setup
→ HTTP 200 {"code":200,"message":"success"}
GET /api/public/init_status
→ initialized:true, ready:true, db_trusted:true, db_load_error:null
说明:未能取到服务端堆栈 —— Workers Observability 需重新部署才会嵌入新版本生效,期间反复触发也拿不到日志。上述结论由源码逐行比对 + 控制台配额提示 + 变量对照实验三者交叉验证得出。
相关配置(必填)
// Cloudflare Dashboard → openlist-worker → 设置 → 运行时变量和密钥(生产)
ENVIRONMENT = production
DB_CIPHER = none
DB_FORMAT = key // ← 出问题的值;改为 map 后正常
DB_DRIVER = kv
JWT_SECRET = (密钥/Secret 类型)
// 绑定
KV → openlist-worker-kv
// wrangler.jsonc(仓库侧,与 Dashboard 一致)
"vars": { "ENVIRONMENT": "production", "DB_CIPHER": "none", "DB_FORMAT": "key", "DB_DRIVER": "kv" }
部署方式:GitHub 连接自动部署(fork 自 OpenListTeam/OpenList-Worker)
账户类型:Cloudflare Workers 免费版
复现链接(可选)
复现站点:https://list.zhuyongfu.cn (当前已切为 map 正常运行,故暂不可在线复现)
最小复现步骤:
- Cloudflare Workers 新建 Worker,绑定一个 KV 命名空间,binding 名
KV - 设置变量
DB_DRIVER=kv、DB_FORMAT=key、JWT_SECRET=<任意32字节随机串> - 部署后访问
https://<域名>/@init - 环境检查显示「存储 就绪 / JWT 密钥 就绪」,点「继续」,填写管理员用户名与密码后提交
POST /api/public/init/setup返回 500
最小代码级复现(在任意 CF Worker 中执行):
const page = await env.KV.list({ prefix: "user:", limit: 256 })
console.log(page.list_complete, page.keys[0]?.name) // true, "user:1"
console.log(page.complete, page.keys[0]?.key) // undefined, undefined ← kv.ts 正在读的就是这两个
参考:
- Cloudflare KV list API:https://developers.cloudflare.com/kv/api/list-keys/
- 同仓库
cfkv.ts中已有正确的 Cloudflare 语义实现,可对照修复
- Dominant language
- TypeScript
- Stars
- 573
- Forks
- 926
- Avg merge
- 3d 1h
- Merged PRs (30d)
- 27
Getting set up
- No Dockerfile or Docker Compose file
- Has a pull request template
- Read the contributing guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from OpenListTeam/OpenList-Worker
-
[BUG] 139云盘139 Cloud token is near expiry; configure user_domain_id to use the PC refreshToken APIOpenbug
Difficulty 3/5 1-2 days Newbie friendliness 47/100
OpenListTeam/OpenList-Worker#122 · 1 comment ·
Maintainers usually reply within 2 days
-
enhancement
Difficulty 4/5 3-5 days Newbie friendliness 22/100
OpenListTeam/OpenList-Worker#115 · 2 comments ·
Maintainers usually reply within 2 days
-
[BUG] 移动云盘访问子目录出现根目录套娃情况Possibly taken @PIKACHUIM claimed this 2 days ago. Openbug
Difficulty 3/5 1-2 days Newbie friendliness 56/100
OpenListTeam/OpenList-Worker#112 · 6 comments ·
Maintainers usually reply within 2 days
All issues in OpenListTeam/OpenList-Worker
Similar issues
-
priority:high
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 65/100
immich-app/immich#32426 ·
Maintainers usually reply within 1 day
-
documentation good first issue hacktoberfest help wanted
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
libredb/libredb-studio#1756 ·
Maintainers usually reply within 1 day
-
state:triage-needed
Difficulty 2/5 1-3 hours Newbie friendliness 62/100
Maintainers usually reply within 1 day