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

  1. Add a branch for the additional item.type_ (e.g. render a folder title as HTML).
  2. Avoid linking to item types the renderer does not support.
  3. 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

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.