laurent22/joplin · error · Error

Cannot find "%s".

Error message

Cannot find "%s".

What it means

Thrown by the `set` command when `app().loadItems(ModelType.Note, title)` returns an empty array, meaning no note matches the supplied title pattern. The command edits a named property on each matched note, so zero matches is a hard stop. `%s` is replaced with the requested note title so the user can see what failed to resolve.

Source

Thrown at packages/app-cli/app/command-set.ts:32

		const fields = Note.fields();
		const s = [];
		for (let i = 0; i < fields.length; i++) {
			const f = fields[i];
			if (f.name === 'id') continue;
			s.push(`${f.name} (${Database.enumName('fieldType', f.type)})`);
		}

		return _('Sets the property <name> of the given <note> to the given [value]. Possible properties are:\n\n%s', s.join(', '));
	}

	public override async action(args: { note: string; name: string; value?: string }) {
		const title = args['note'];
		const propName = args['name'];
		let propValue = args['value'];
		if (!propValue) propValue = '';

		const notes = await app().loadItems(ModelType.Note, title);
		if (!notes.length) throw new Error(_('Cannot find "%s".', title));

		for (let i = 0; i < notes.length; i++) {
			this.encryptionCheck(notes[i]);

			const timestamp = Date.now();

			const newNote: Record<string, unknown> = {
				id: notes[i].id,
				type_: notes[i].type_,
				updated_time: timestamp,
			};
			newNote[propName] = propValue;

			if (!newNote.id) newNote.created_time = timestamp;

			await Note.save(newNote, {
				autoTimestamp: false, // No auto-timestamp because user may have provided them
			});

View on GitHub (pinned to 2654b33620)

Solutions

  1. List notes with `:ls` or `find <pattern>` to copy the exact title, then re-run `:set`.
  2. If the notebook is encrypted, run `:e2ee decrypt` to supply the password and decrypt titles first.
  3. Pass the note id instead of the title if the title is ambiguous or hard to type.
  4. Verify you are in the right profile (`--profile`) that actually contains the note.

Example fix

// before
const notes = await app().loadItems(ModelType.Note, title);
if (!notes.length) throw new Error(_('Cannot find "%s".', title));

// after - also accept an explicit id and give a clearer message
const notes = await app().loadItems(ModelType.Note, title);
if (!notes.length) throw new Error(_('Cannot find note "%s". Use `:ls` to list note titles.', title));
Defensive patterns

Strategy: validation

Validate before calling

const notes = await app().loadItems(ModelType.Note, title);
if (!notes.length) {
	throw new Error(`No note matches "${title}". Use the note id or run \`:ls\`.`);
}

Type guard

const hasMatch = <T>(arr: T[]): arr is T[] => Array.isArray(arr) && arr.length > 0;

Try / catch

try {
	await app().executeCommand(['set', noteTitle, propName, value]);
} catch (e) {
	if (/Cannot find/.test(e.message)) { /* re-list notes / decrypt titles */ }
	else throw e;
}

Prevention

When it happens

Trigger: Running `:set <note> <name> [value]` where `<note>` does not match any Note.title (loadItems matches by title or id pattern). Also when the note exists but is inside an encrypted notebook whose title has not been decrypted yet, so the plaintext title is unknown to the loader.

Common situations: Mistyped note title; note was deleted or moved off-profile; E2EE-encrypted notes whose titles are still ciphertext; title pattern that is a partial match the loader does not accept.

Related errors


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