laurent22/joplin · warning · Error
Unsupported item type: ${item.type_}
Error message
Unsupported item type: ${item.type_} What it means
After the link handler loads the referenced item by id, it only knows how to render two kinds: TYPE_RESOURCE (writes the binary content with its mime Content-Type) and TYPE_NOTE (writes an HTML document with the title and body). For any other item.type_ (e.g. Folder, Tag, etc.) it throws 'Unsupported item type'. The throw is caught by ResourceServer and returned as a 400.
Source
Thrown at packages/app-cli/app/app-gui.ts:729
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_}`);
}
return true;
}
return false;
});
await this.resourceServer_.start();
if (!this.resourceServer_.started()) return;
noteTextWidget.markdownRendererOptions = {
linkUrlRenderer: (index: number, url: string) => {
if (!url) return url;
if (resourceIdRegex.test(url)) {
noteLinks[index] = {
type: 'item',View on GitHub (pinned to 2654b33620)
Solutions
- Add a branch for the additional item.type_ (e.g. render a folder title as HTML).
- Avoid linking to item types the renderer does not support.
- Write a fallback response and return true for unsupported types instead of throwing.
Example fix
// before
// } else {
// throw new Error(`Unsupported item type: ${item.type_}`);
// }
// after
// } else {
// response.statusCode = 415;
// response.write(`Cannot render item type: ${item.type_}`);
// }
// return true; Defensive patterns
Strategy: type-guard
Validate before calling
const RENDERABLE_TYPES = [BaseModel.TYPE_RESOURCE, BaseModel.TYPE_NOTE];
if (!RENDERABLE_TYPES.includes(item.type_)) {
response.statusCode = 415;
response.write(`Cannot render item type: ${item.type_}`);
return true;
} Type guard
const isRenderableItemType = (item: { type_: number }): boolean =>
item.type_ === BaseModel.TYPE_RESOURCE || item.type_ === BaseModel.TYPE_NOTE; Prevention
- Render only resource and note links; warn the user about other link targets.
- When adding a new sync item type, decide whether the resource server should render it and add a branch if so.
When it happens
Trigger: An internal link points to an item whose type_ is neither a resource nor a note — for example a link to a notebook/folder (:/folderId) or a tag embedded in note markdown.
Common situations: A user manually constructs or pastes a link to a non-note/resource item; future item types are added to the sync model set without updating the renderer; a corrupted type_ value on a row.
Related errors
AI-assisted analysis of laurent22/joplin@2654b33620 (2026-08-12).
Data as JSON: /api/errors/4cb6358c734aa757.
Report an issue: GitHub.