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
- Trigger a sync so the referenced item is downloaded into the local database.
- Remove or repair the dangling internal link in the note markdown.
- 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
- Treat loadItemById results as nullable and write a user-facing message instead of throwing inside the HTTP handler.
- Sync before opening notes whose links may reference items not yet on this device.
- Periodically prune or flag dangling internal links in notes.
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
- Unsupported item type: ${item.type_}
- Please specify the sync target path.
- Unhandled resource: ${resourceId}
- Cannot change encrypted item
- Cannot find "%s".
AI-assisted analysis of laurent22/joplin@2654b33620 (2026-08-12).
Data as JSON: /api/errors/0419ef0a8b5fcab2.
Report an issue: GitHub.