laurent22/joplin · error · Error
${mode} access is needed for ${id}.
Error message
${mode} access is needed for ${id}. What it means
Thrown by the web-worker RN fs-driver's `mountExternalDirectory` when `handle.requestPermission({ mode })` does not return 'granted' for the requested access mode (`read` or `readwrite`). The mode and the mount id are interpolated so the caller knows which mount failed and what access it needed.
Source
Thrown at packages/app-mobile/utils/fs-driver/fs-driver-rn.web.worker.ts:517
return true;
}
throw error;
}
}
public async md5File(path: string): Promise<string> {
const fileData = Buffer.from(await (await this.fileAtPath(path)).arrayBuffer());
return md5(fileData);
}
public async createReadOnlyVirtualFile(path: string, content: File) {
this.virtualFiles_.set(normalize(path), content);
}
public async mountExternalDirectory(handle: FileSystemDirectoryHandle, id: string, mode: AccessMode) {
if (await handle.requestPermission({ mode }) !== 'granted') {
throw new Error(`${mode} access is needed for ${id}.`);
}
const mountPath = resolve(externalDirectoryPrefix, crypto.randomUUID().replace(/-/g, ''));
this.externalHandles_.set(mountPath, handle);
await this.accessHandleDatabase_.clearExternalHandle(id);
await this.accessHandleDatabase_.addExternalHandle(mountPath, id, handle, mode);
return mountPath;
}
}
interface RemoteApi { }
new WorkerToWindowMessenger<WorkerApi, RemoteApi>('fs-worker', new WorkerApi());
View on GitHub (pinned to 2654b33620)
Solutions
- Prompt the user to allow access and retry; if previously denied, instruct them to clear site permissions first.
- Fall back to requesting 'read' mode if read-write is refused and write is not strictly required.
- Pre-check with `handle.queryPermission({ mode })` and only call `requestPermission` when state is 'prompt'.
- Handle the error in the UI and offer to pick a different folder.
Example fix
// before
await driver.mountExternalDirectory(handle, id, 'readwrite');
// after
if (await handle.queryPermission({ mode }) === 'prompt') {
if (await handle.requestPermission({ mode }) !== 'granted') {
throw new Error(`${mode} access is needed for ${id}.`);
}
}
await driver.mountExternalDirectory(handle, id, mode); Defensive patterns
Strategy: validation
Validate before calling
if (await handle.queryPermission({ mode }) === 'prompt') {
if (await handle.requestPermission({ mode }) !== 'granted') {
throw new Error(`${mode} access is needed for ${id}.`);
}
} Type guard
const isAccessMode = (m: unknown): m is 'read' | 'readwrite' => m === 'read' || m === 'readwrite';
Try / catch
try {
await driver.mountExternalDirectory(handle, id, mode);
} catch (error) {
if (/access is needed for/i.test(error.message)) {
await showPermissionDeniedHelp(id, mode);
return;
}
throw error;
} Prevention
- Call queryPermission before requestPermission to avoid useless prompts after a denial.
- Fall back to read-only when readwrite is refused and write is optional.
- On persistent denial, instruct the user to reset site permissions.
When it happens
Trigger: Calling `mountExternalDirectory(handle, id, mode)` where the user denies the browser permission prompt, or the handle's state was already 'denied' so the prompt cannot be shown again.
Common situations: User clicked 'Block' on the permission prompt; the site previously had its permission revoked at browser level; requesting 'readwrite' when the underlying file system is read-only.
Related errors
- Missing read-write access. It might be necessary to share th
- Could not read directory: ${path}: ${error.message}
- No model found at path: ${JSON.stringify(modelFolderPath)}
- Model not found at path ${modelPath}
- Error! Destination already exists
AI-assisted analysis of laurent22/joplin@2654b33620 (2026-08-12).
Data as JSON: /api/errors/996290c39d6d144f.
Report an issue: GitHub.