laurent22/joplin · error · Error
No such folder: ${folderId}
Error message
No such folder: ${folderId} What it means
Thrown by ShareService.unpublishFolder() when Folder.load(folderId) returns null, meaning no folder with that ID exists in the local database. Share operations run entirely against the local Joplin database (not the server), so the folder must have been synced to this device before it can be unpublished. The error is a plain guard clause at the top of the method, before any share state or network call is touched.
Source
Thrown at packages/lib/services/share/ShareService.ts:327
}
public async publishFolder(folderId: string): Promise<StateShare> {
const folder = await Folder.load(folderId);
if (!folder) throw new Error(`No such folder: ${folderId}`);
const share = await this.api().exec('POST', 'api/shares', {}, {
folder_id: folderId,
type: ShareType.PublishedFolder,
});
await this.refreshShares();
return share;
}
public async unpublishFolder(folderId: string): Promise<void> {
const folder = await Folder.load(folderId);
if (!folder) throw new Error(`No such folder: ${folderId}`);
const share = this.shares.find(s => s.type === ShareType.PublishedFolder && s.folder_id === folderId);
if (!share) throw new Error(`No published share for folder: ${folderId}`);
const remainingShares = this.shares.filter(s => s.id !== share.id);
const folderIds = [folderId, ...(await Folder.allChildrenFolders(folderId)).map(f => f.id)];
const folders = await Folder.loadItemsByIds(folderIds) as FolderEntity[];
const noteIds = (await Promise.all(folderIds.map(id => Folder.noteIds(id, { includeConflicts: true, includeDeleted: true })))).flat();
const notes = await Note.loadItemsByIds(noteIds) as NoteEntity[];
const directlyPublishedNoteIds = new Set(remainingShares
.filter(s => s.type === ShareType.Note && !!s.note_id)
.map(s => s.note_id));
for (const folderItem of folders) {
await Folder.updateShareStatus({ ...folderItem, type_: ModelType.Folder }, false);
}
for (const note of notes) {View on GitHub (pinned to dc4e0b464e)
Solutions
- Verify the folder exists locally first: const folder = await Folder.load(folderId) and bail or re-render if null.
- Make sure sync has run to completion on this device so the folder row exists before invoking share operations.
- Check the ID source: confirm you are passing the folder's id (not parent_id, not a note id, not a share id).
- If the folder was deleted intentionally, treat 'No such folder' as success (nothing left to unpublish) instead of letting it bubble up.
Example fix
// before await shareService.unpublishFolder(folderId); // after const folder = await Folder.load(folderId); if (!folder) return; // nothing to unpublish locally await shareService.unpublishFolder(folderId);
Defensive patterns
Strategy: validation
Validate before calling
import { Folder } from '@joplin/lib/models/Folder';
const folder = await Folder.load(folderId);
if (!folder) {
// Folder is not in the local database: resync, or treat as nothing-to-unpublish
return;
} Type guard
const isExistingFolder = (f: FolderEntity | null): f is FolderEntity => !!f;
Try / catch
try {
await shareService.unpublishFolder(folderId);
} catch (error) {
if (error instanceof Error && error.message.startsWith('No such folder:')) {
// Local DB lacks the folder: run a sync and retry once, or accept as no-op
} else {
throw error;
}
} Prevention
- Always resolve entities from the local database (Folder.load) before passing their IDs into share operations.
- Ensure sync has completed on this device before exposing publish/unpublish actions.
- Never reuse folder IDs captured in a previous session without re-validating them.
When it happens
Trigger: Calling unpublishFolder(folderId) with an ID that is not in the local folders table: a typo'd/truncated ID, an ID from a different profile or device that was never synced, a folder already deleted locally (e.g. in the trash or removed by a previous sync), or passing a note ID where a folder ID is expected.
Common situations: Scripts or plugins that capture a folder ID, delete/recreate the folder, then call unpublish with the stale ID; UI acting on a stale selection after the folder was deleted on another device and synced away; multi-profile setups where the ID belongs to another profile's database.
Understand the failure class
Background: "Not found" and "does not exist" errors: why "Task not found", "No such folder", and "Can't find" fire when a lookup comes back empty — this error's family across 14 libraries.
Related errors
- No such note: ${noteId}
- Cannot find "%s".
- No published share for folder: ${folderId}
- No share found for folder ${folderId}
- No share found for folder ${folder.id}
AI-assisted analysis of laurent22/joplin@dc4e0b464e (2026-08-21).
Data as JSON: /api/errors/34b34a4a9e237353.
Report an issue: GitHub.