Summary
In a Feishu drive folder with more files than one API page, feishu_drive action: info returns a false File not found: <token> for any file that lives beyond the first page, and action: list cannot retrieve any page after the first. Both surfaces ignore the has_more / next_page_token cursor the Lark API returns, so files past page 1 are silently inaccessible.
Environment
- Commit: cc451f9 (origin/main at time of filing)
- Surface: Feishu plugin
feishu_drive tool, list and info actions (extensions/feishu/src/drive.ts, extensions/feishu/src/drive-schema.ts)
Steps to reproduce
- Have a Feishu drive folder with more files than fit in one
drive.file.list page (the API signals this with has_more: true and a next_page_token).
- Call
feishu_drive action: info with the file_token of a file that sorts onto page 2 or later.
- Or call
feishu_drive action: list on that folder and try to fetch the next page.
Expected
info follows has_more / next_page_token until it finds the file, then returns its metadata.
list accepts a page cursor so the caller can page through the whole folder, and reports whether more pages remain.
Actual
info searches only the first page and throws File not found: <token> for any file past page 1, even though the file exists and the API advertised more pages.
list returns only the first page. The action schema exposes no page_token, so the returned next_page_token can never be fed back, and pages 2+ are unreachable.
Root cause
getFileInfo (extensions/feishu/src/drive.ts:356) does a single first-page .find() and throws when absent, never following has_more:
async function getFileInfo(client: Lark.Client, fileToken: string, folderToken?: string) {
// Use list with folder_token to find file info
const res = await client.drive.file.list({
params: folderToken ? { folder_token: folderToken } : {},
});
if (res.code !== 0) {
throw new Error(res.msg);
}
const file = res.data?.files?.find((f) => f.token === fileToken);
if (!file) {
throw new Error(`File not found: ${fileToken}`);
}
// ...
}
listFolder (extensions/feishu/src/drive.ts:331) passes no page_token and the list action schema (extensions/feishu/src/drive-schema.ts:25) exposes none, so the next_page_token it does return at drive.ts:352 can never be supplied on a follow-up call:
async function listFolder(client: Lark.Client, folderToken?: string) {
const validFolderToken = folderToken && folderToken !== "0" ? folderToken : undefined;
const res = await client.drive.file.list({
params: validFolderToken ? { folder_token: validFolderToken } : {},
});
// ... returns next_page_token but the dispatch (drive.ts:770-773) accepts no cursor to send back
}
The Lark SDK @larksuiteoapi/node-sdk drive.file.list accepts page_size / page_token and returns next_page_token / has_more (and offers a listWithIterator). The plugin reads neither cursor field on this path.
Sibling surfaces
This is the direct sibling-class of the just-merged wiki pagination fix #37626 (commit 5f90f08), which paginated wiki.spaceNode.list / wiki.space.list in wiki.ts + wiki-schema.ts but did not touch drive.ts. The same plugin's comment paths already paginate correctly: list_comments and list_comment_replies expose page_size + page_token in the schema (drive-schema.ts:54-66) and read has_more / page_token from the response (drive.ts:486-487, 519-520). So the drive list / info omission is the lone un-paginated lister in the plugin. Checked the open Feishu PRs (tool-family gates, card/proactive send, topic queue, audit redaction, URL challenge, streaming card coalescing); none touch drive list / info.
Real behavior proof
Behavior addressed: feishu_drive info must find a file that lives past the first drive.file.list page instead of falsely reporting File not found.
Real environment tested: real registerFeishuDriveTools runtime driven end to end through the tool's execute dispatch and getFileInfo, with client.drive.file.list mocked to return the target on page 2 with has_more: true + next_page_token, at commit cc451f9.
Exact steps or command run after this patch: node scripts/run-vitest.mjs extensions/feishu/src/drive.pagination.repro.test.ts (the repro registers the real drive tool, calls action: info for a token that sorts to page 2, and asserts the lister is drained to 2 pages and the file is returned).
Evidence after fix:
# OBSERVED (buggy, origin/main cc451f98cbae)
FAIL extensions/feishu/src/drive.pagination.repro.test.ts > info finds a file that lives past the first page
AssertionError: expected "vi.fn()" to be called 2 times, but got 1 times
115| expect(listMock).toHaveBeenCalledTimes(2);
| ^
-> getFileInfo queried only page 1 (one list call) and threw "File not found: target";
list was never asked for page 2 despite has_more: true.
# EXPECTED (correct behavior on identical inputs, with the local fix applied)
Test Files 2 passed (2)
Tests 16 passed (16)
-> getFileInfo drains has_more/next_page_token to page 2 (two list calls), finds and
returns the file. Existing drive.test.ts stays green (15 tests), 16 total.
Observed result after fix: on unmodified main, info silently fails for files past page 1 (list called once, throws File not found); draining pages following has_more/next_page_token fixes it without regressing existing drive behavior.
What was not tested: not run against a live Feishu tenant; the proof drives the real plugin code path with the Lark drive.file.list response shape mocked rather than a live multi-page folder. The list action was not exercised in the automated repro (its defect is structural: the schema exposes no page_token cursor, shown above), only info was driven end to end.
Summary
In a Feishu drive folder with more files than one API page,
feishu_driveaction: inforeturns a falseFile not found: <token>for any file that lives beyond the first page, andaction: listcannot retrieve any page after the first. Both surfaces ignore thehas_more/next_page_tokencursor the Lark API returns, so files past page 1 are silently inaccessible.Environment
feishu_drivetool,listandinfoactions (extensions/feishu/src/drive.ts,extensions/feishu/src/drive-schema.ts)Steps to reproduce
drive.file.listpage (the API signals this withhas_more: trueand anext_page_token).feishu_driveaction: infowith thefile_tokenof a file that sorts onto page 2 or later.feishu_driveaction: liston that folder and try to fetch the next page.Expected
infofollowshas_more/next_page_tokenuntil it finds the file, then returns its metadata.listaccepts a page cursor so the caller can page through the whole folder, and reports whether more pages remain.Actual
infosearches only the first page and throwsFile not found: <token>for any file past page 1, even though the file exists and the API advertised more pages.listreturns only the first page. The action schema exposes nopage_token, so the returnednext_page_tokencan never be fed back, and pages 2+ are unreachable.Root cause
getFileInfo(extensions/feishu/src/drive.ts:356) does a single first-page.find()and throws when absent, never followinghas_more:listFolder(extensions/feishu/src/drive.ts:331) passes nopage_tokenand thelistaction schema (extensions/feishu/src/drive-schema.ts:25) exposes none, so thenext_page_tokenit does return atdrive.ts:352can never be supplied on a follow-up call:The Lark SDK
@larksuiteoapi/node-sdkdrive.file.listacceptspage_size/page_tokenand returnsnext_page_token/has_more(and offers alistWithIterator). The plugin reads neither cursor field on this path.Sibling surfaces
This is the direct sibling-class of the just-merged wiki pagination fix #37626 (commit 5f90f08), which paginated
wiki.spaceNode.list/wiki.space.listinwiki.ts+wiki-schema.tsbut did not touchdrive.ts. The same plugin's comment paths already paginate correctly:list_commentsandlist_comment_repliesexposepage_size+page_tokenin the schema (drive-schema.ts:54-66) and readhas_more/page_tokenfrom the response (drive.ts:486-487,519-520). So the drivelist/infoomission is the lone un-paginated lister in the plugin. Checked the open Feishu PRs (tool-family gates, card/proactive send, topic queue, audit redaction, URL challenge, streaming card coalescing); none touch drivelist/info.Real behavior proof
Behavior addressed:
feishu_driveinfomust find a file that lives past the firstdrive.file.listpage instead of falsely reportingFile not found.Real environment tested: real
registerFeishuDriveToolsruntime driven end to end through the tool'sexecutedispatch andgetFileInfo, withclient.drive.file.listmocked to return the target on page 2 withhas_more: true+next_page_token, at commit cc451f9.Exact steps or command run after this patch:
node scripts/run-vitest.mjs extensions/feishu/src/drive.pagination.repro.test.ts(the repro registers the real drive tool, callsaction: infofor a token that sorts to page 2, and asserts the lister is drained to 2 pages and the file is returned).Evidence after fix:
Observed result after fix: on unmodified main, info silently fails for files past page 1 (list called once, throws File not found); draining pages following has_more/next_page_token fixes it without regressing existing drive behavior.
What was not tested: not run against a live Feishu tenant; the proof drives the real plugin code path with the Lark
drive.file.listresponse shape mocked rather than a live multi-page folder. Thelistaction was not exercised in the automated repro (its defect is structural: the schema exposes nopage_tokencursor, shown above), onlyinfowas driven end to end.