laurent22/joplin · warning · Error

No item with ID ${itemId}

Error message

No item with ID ${itemId}

What it means

Inside the resource-server link handler, an internal link of type 'item' is resolved by loading the referenced item from the database via BaseItem.loadItemById(itemId). loadItemById iterates the sync item classes and returns null if no class has a row with that id. If the result is null the handler throws 'No item with ID'. The source comment marks this 'Should be nearly impossible', and the throw is caught by ResourceServer and turned into a 400 response.

Source

Thrown at packages/app-cli/app/app-gui.ts:712

					return url;
				}
			},
		};

		this.resourceServer_ = new ResourceServer();
		this.resourceServer_.setLogger(this.app().logger());
		this.resourceServer_.setLinkHandler(async (path, response) => {
			const link = noteLinks[path];

			if (link.type === 'url') {
				response.writeHead(302, { Location: link.url });
				return true;
			}

			if (link.type === 'item') {
				const itemId = link.id;
				const item = await BaseItem.loadItemById(itemId);
				if (!item) throw new Error(`No item with ID ${itemId}`); // Should be nearly impossible

				if (item.type_ === BaseModel.TYPE_RESOURCE) {
					if (item.mime) response.setHeader('Content-Type', item.mime);
					response.write(await Resource.content(item));
				} else if (item.type_ === BaseModel.TYPE_NOTE) {
					const html = [
						`
						<!DOCTYPE html>
						<html class="client-nojs" lang="en" dir="ltr">
						<head><meta charset="UTF-8"/></head><body>
					`,
					];
					html.push(`<pre>${htmlentities(item.title)}\n\n${htmlentities(item.body)}</pre>`);
					html.push('</body></html>');
					response.write(html.join(''));
				} else {
					throw new Error(`Unsupported item type: ${item.type_}`);
				}

View on GitHub (pinned to 2654b33620)

Solutions

  1. Trigger a sync so the referenced item is downloaded into the local database.
  2. Remove or repair the dangling internal link in the note markdown.
  3. Handle the null result gracefully by writing a 'resource not found' message to the response and returning true, instead of throwing.

Example fix

// before
//   const item = await BaseItem.loadItemById(itemId);
//   if (!item) throw new Error(`No item with ID ${itemId}`);
// after
//   const item = await BaseItem.loadItemById(itemId);
//   if (!item) {
//     response.statusCode = 404;
//     response.write(`Item not found: ${itemId}`);
//     return true;
//   }
Defensive patterns

Strategy: validation

Validate before calling

const item = await BaseItem.loadItemById(itemId);
if (!item) {
  response.statusCode = 404;
  response.write(`Item not found: ${itemId}`);
  return true;
}

Prevention

When it happens

Trigger: A note contains an internal link (joplin:///:/itemId) whose target has been deleted; the link id is truncated or corrupted; the referenced item has not yet been synced to this device so it is absent from the local database.

Common situations: Opening a note on a freshly synced device where linked items have not downloaded yet; dangling links left after deleting a linked note/resource; manual or partial database edits that orphan an id.

Related errors


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