laurent22/joplin · error · Error

Notebooks cannot be named "%s", which is a reserved title.

Error message

Notebooks cannot be named "%s", which is a reserved title.

What it means

Thrown by Folder.save when options.reservedTitleCheck is true and o.title exactly equals Folder.conflictFolderTitle(), which returns the localized string for 'Conflicts' (packages/lib/models/Folder.ts:195). That title is reserved for Joplin's built-in conflict notebook (Folder.conflictFolder / getConflictFolderId), so letting a user create one would collide with the reserved id and corrupt conflict resolution. reservedTitleCheck defaults on only when userSideValidation is true.

Source

Thrown at packages/lib/models/Folder.ts:1118

			}
		}

		// We allow folders with duplicate titles so that folders with the same title can exist under different parent folder. For example:
		//
		// PHP
		//     Code samples
		//     Doc
		// Java
		//     My project
		//     Doc

		// if (options.duplicateCheck === true && o.title) {
		// 	let existingFolder = await Folder.loadByTitle(o.title);
		// 	if (existingFolder && existingFolder.id != o.id) throw new Error(_('A notebook with this title already exists: "%s"', o.title));
		// }

		if (options.reservedTitleCheck === true && o.title) {
			if (o.title === Folder.conflictFolderTitle()) throw new Error(_('Notebooks cannot be named "%s", which is a reserved title.', o.title));
		}

		syncDebugLog.info('Folder Save:', o);

		let savedFolder: FolderEntity = await super.save(o, options);

		// Ensures that any folder added to the state has all the required
		// properties, in particular "share_id" and "parent_id', which are
		// required in various parts of the code.
		if (!('share_id' in savedFolder) || !('parent_id' in savedFolder) || !('deleted_time' in savedFolder)) {
			savedFolder = await this.load(savedFolder.id);
		}

		this.dispatch({
			type: 'FOLDER_UPDATE_ONE',
			item: savedFolder,
		});

View on GitHub (pinned to 2654b33620)

Solutions

  1. In the rename/create UI, block or auto-suffix titles equal to Folder.conflictFolderTitle() before calling save.
  2. If the user genuinely wants a notebook named 'Conflicts', pick an alternate spelling or suffix (e.g. 'Conflicts (personal)') — the exact reserved string is the only blocked value.
  3. For non-user-initiated persistence (import/sync replay), omit userSideValidation/reservedTitleCheck so the reserved check does not apply.
  4. Compare against the localized conflictFolderTitle() (not a hard-coded English string) so the guard is correct across locales.

Example fix

// before
folder.title = newTitle;
await Folder.save(folder, { userSideValidation: true });

// after
if (newTitle === Folder.conflictFolderTitle()) {
  throw new Error(`The name "${newTitle}" is reserved; choose a different notebook title.`);
}
folder.title = newTitle;
await Folder.save(folder, { userSideValidation: true });
Defensive patterns

Strategy: validation

Validate before calling

// Block the reserved conflict title (locale-aware) before saving.
function isReservedTitle(title: string): boolean {
  return Boolean(title) && title === Folder.conflictFolderTitle();
}

if (isReservedTitle(folder.title)) {
  throw new Error(`"${folder.title}" is a reserved notebook name.`);
}

Try / catch

try {
  await Folder.save(folder, { userSideValidation: true });
} catch (error) {
  if (error.message.startsWith('Notebooks cannot be named')) {
    // Prompt the user for a different name; re-render the rename dialog.
    return showRenameError(error.message);
  }
  throw error;
}

Prevention

When it happens

Trigger: Calling Folder.save(folder, { userSideValidation: true }) (which auto-enables reservedTitleCheck) — or passing reservedTitleCheck: true directly — with o.title set to the localized word for 'Conflicts' (e.g. 'Conflicts' in English, the translated term in other locales). Exact, case-sensitive equality only.

Common situations: A user typing 'Conflicts' as a notebook name in the UI; a rename operation hitting the reserved word; localized builds where the user typed the translated conflict title; import scripts that create notebooks from arbitrary external names without filtering reserved words.

Related errors


AI-assisted analysis of laurent22/joplin@2654b33620 (2026-08-12). Data as JSON: /api/errors/51cef207cfee450c. Report an issue: GitHub.