laurent22/joplin · error · Error

Cannot move item with type ${itemType}

Error message

Cannot move item with type ${itemType}

What it means

Thrown by the moveToFolder command when an item being moved has a type_ that is neither ModelType.Note nor ModelType.Folder. The command dispatches per-type (Note.moveToFolder / Folder.moveToFolder); any other item type (resource, tag, etc.) has no move semantics and is rejected.

Source

Thrown at packages/app-desktop/gui/WindowCommandsAndDialogs/commands/moveToFolder.ts:58

				showFolder: (folder) => !itemIdToType.has(folder.id),
			});

			// It's important to allow the case where targetFolderId is the empty string,
			// since that corresponds to the toplevel notebook.
			if (targetFolderId !== null) {
				try {
					for (const id of itemIds) {
						if (id === targetFolderId) {
							continue;
						}

						const itemType = itemIdToType.get(id);
						if (itemType === ModelType.Note) {
							await Note.moveToFolder(id, targetFolderId);
						} else if (itemType === ModelType.Folder) {
							await Folder.moveToFolder(id, targetFolderId);
						} else {
							throw new Error(`Cannot move item with type ${itemType}`);
						}
					}
				} catch (error) {
					logger.error('Error moving items', error);
					void shim.showMessageBox(`Error: ${error}`);
				}
			}
		},
		enabledCondition: 'someNotesSelected && !noteIsReadOnlyShare',
	};
};

View on GitHub (pinned to 2654b33620)

Solutions

  1. Filter the selection to only Note and Folder items before invoking move.
  2. Verify itemIdToType is populated correctly for every selected ID.
  3. Skip unsupported item types with a warning instead of aborting the whole move.
  4. In the UI, disable the move action when the selection contains non-movable types.

Example fix

// before
} else {
  throw new Error(`Cannot move item with type ${itemType}`);
}

// after — skip unsupported types, log, continue
} else {
  logger.warn(`Skipping item ${id}: cannot move type ${itemType}`);
  continue;
}
Defensive patterns

Strategy: validation

Validate before calling

const movableIds = itemIds.filter(id => {
  const t = itemIdToType.get(id);
  return t === ModelType.Note || t === ModelType.Folder;
});
// pass only movableIds to the move loop

Type guard

function isMovableType(type: ModelType): boolean {
  return type === ModelType.Note || type === ModelType.Folder;
}

Try / catch

try {
  await moveToFolderRuntime.execute(ctx, itemIds, targetFolderId);
} catch (e) {
  if (e.message.startsWith('Cannot move item with type')) {
    // filter the selection to notes/folders and retry
  } else throw e;
}

Prevention

When it happens

Trigger: The user (or a script) selects a mix of items including at least one non-note/non-folder (e.g. a resource or a tag) and triggers move. itemIdToType.get(id) returns a ModelType value that falls through both branches to the else.

Common situations: Multi-select in a view that includes resources or other item types alongside notes/folders; a plugin constructs itemIds from a heterogeneous list; the type map was built incorrectly and reports a stale or wrong type for an ID.

Related errors


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