You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Directory picker caches failed listings until the dialog is reopened #49518
On dev 88c6c7a, createDirectorySearch caches a rejected directory listing as a successful empty array. If the connection or directory permissions recover, typing again in the same dialog cannot discover its children. Reopening the dialog is required.
Related to #41412 and #39434. The home-listing fallback from #41158 is already merged; this is a remaining recovery bug.
Open the directory picker and make its first file.list request fail.
Restore access and search the same directory again.
The cached empty result prevents another request.
A regression test against the real createDirectorySearch fails before evicting rejected listings and passes after. Successful listings remain cached. I can submit the small fix with that test.
Thanks for the clear report. I reproduced this, and it still happens on the latest dev (950111f).
The test below runs the real createDirectorySearch against a mock SDK whose first file.list call rejects and whose later calls succeed. Searching /tmp/ twice in the same search instance returns [] both times, and file.list is called only once. The rejected request is cached as an empty listing, so it is never retried until the dialog is reopened. Successful listings stay cached as intended.
Removing the entry from the cache when the request fails makes the test pass, along with the existing tests in that folder.
Related: #39434 (empty listing from a missing path parameter) and #41412 (listing $HOME, fixed in #41158). Both are closed and are different problems.
// Reproduction for anomalyco/opencode#49518: createDirectorySearch caches a// rejected file.list as a successful empty listing for the life of the dialog.//// Run from a dev checkout:// cp directory-search-cache.test.ts packages/app/src/workspaces/selection/// cd packages/app && bun test src/workspaces/selection/directory-search-cache.test.tsimport{expect,test}from"bun:test"import{createDirectorySearch,listPickerDirectory}from"./domain"typeSdk=Parameters<typeoflistPickerDirectory>[0]consttree: Record<string,Array<{path: string;type: "directory"|"file"}>>={"": [{path: "tmp/",type: "directory"}],"/": [{path: "tmp/",type: "directory"}],"/tmp": [{path: "/tmp/project-a/",type: "directory"},{path: "/tmp/project-b/",type: "directory"},],}constmock=(failFirst: boolean)=>{constlocation={directory: "/"}constcalls: string[]=[]constsdk={api: {file: {find: ()=>Promise.resolve({ location,data: []}),list: (input: {path: string})=>{calls.push(input.path)// The first request fails (connection drop / EACCES); later ones succeed.if(failFirst&&calls.length===1)returnPromise.reject(newError("network down"))returnPromise.resolve({ location,data: tree[input.path.replace(/\/+$/,"")]??[]})},},},}asunknownasSdkconstsearch=createDirectorySearch({ sdk,home: ()=>"",base: ()=>"/",location: ()=>location})return{ search, calls }}test("a failed file.list is retried on the next search in the same dialog",async()=>{const{ search, calls }=mock(true)constfirst=awaitsearch("/tmp/")console.log("first search (list rejected):",first,"file.list calls:",calls)expect(first).toEqual([])constsecond=awaitsearch("/tmp/")console.log("second search (access restored):",second,"file.list calls:",calls)expect(second).toEqual(["/tmp/project-a","/tmp/project-b"])})test("successful listings stay cached",async()=>{const{ search, calls }=mock(false)constfirst=awaitsearch("/tmp/")constcount=calls.lengthexpect(first).toEqual(["/tmp/project-a","/tmp/project-b"])expect(awaitsearch("/tmp/")).toEqual(first)expect(calls.length).toBe(count)})
Activity
opencodejr commentedon Oct 28, 2026
Thanks for the clear report. I reproduced this, and it still happens on the latest
dev(950111f).The test below runs the real
createDirectorySearchagainst a mock SDK whose firstfile.listcall rejects and whose later calls succeed. Searching/tmp/twice in the same search instance returns[]both times, andfile.listis called only once. The rejected request is cached as an empty listing, so it is never retried until the dialog is reopened. Successful listings stay cached as intended.Removing the entry from the cache when the request fails makes the test pass, along with the existing tests in that folder.
Related: #39434 (empty listing from a missing
pathparameter) and #41412 (listing$HOME, fixed in #41158). Both are closed and are different problems.Reproduction script (directory-search-cache.test.ts)
Run it:
bun directory-search-cache.test.ts