{"record":{"id":"4e7655fe39727195","repo":"laurent22/joplin","slug":"cannot-convert-read-only-item-s","errorCode":null,"errorMessage":"Cannot convert read-only item: \"%s\"","messagePattern":"Cannot convert read-only item: \"(.+?)\"","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/lib/commands/convertNoteToMarkdown.ts","lineNumber":42,"sourceCode":"\t\t\tif (typeof noteIds === 'string') {\n\t\t\t\tnoteIds = [noteIds];\n\t\t\t}\n\t\t\tif (noteIds.length === 0) {\n\t\t\t\tnoteIds = context.state.selectedNoteIds;\n\t\t\t}\n\n\t\t\tconst notes: NoteEntity[] = await Note.loadItemsByIdsOrFail(noteIds);\n\n\t\t\ttry {\n\t\t\t\tlet isFirst = true;\n\t\t\t\tlet processedCount = 0;\n\t\t\t\tfor (const note of notes) {\n\t\t\t\t\tif (note.markup_language === MarkupLanguage.Markdown) {\n\t\t\t\t\t\tlogger.warn('Skipping item: Already Markdown.');\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\tif (await itemIsReadOnly(Note, ModelType.Note, ItemChange.SOURCE_UNSPECIFIED, note.id, Setting.value('sync.userId'), context.state.shareService)) {\n\t\t\t\t\t\tthrow new Error(_('Cannot convert read-only item: \"%s\"', note.title));\n\t\t\t\t\t}\n\n\t\t\t\t\tconst markdownBody = await convertHtmlToMarkdown().execute(context, note.body);\n\t\t\t\t\tconst newNote = await Note.duplicate(note.id);\n\n\t\t\t\t\tnewNote.body = markdownBody;\n\t\t\t\t\tnewNote.markup_language = MarkupLanguage.Markdown;\n\t\t\t\t\tnewNote.user_created_time = note.user_created_time;\n\t\t\t\t\tnewNote.user_updated_time = note.user_updated_time;\n\t\t\t\t\tnewNote.updated_time = Date.now();\n\n\t\t\t\t\tawait Note.save(newNote, { autoTimestamp: false });\n\t\t\t\t\tawait Note.delete(note.id, { toTrash: true });\n\t\t\t\t\tprocessedCount ++;\n\n\t\t\t\t\tif (isFirst) {\n\t\t\t\t\t\tcontext.dispatch({\n\t\t\t\t\t\t\ttype: 'NOTE_SELECT',","sourceCodeStart":24,"sourceCodeEnd":60,"githubUrl":"https://github.com/laurent22/joplin/blob/2654b33620775080d1d59c552259d41e33dad3d2/packages/lib/commands/convertNoteToMarkdown.ts#L24-L60","documentation":"Thrown by the convertNoteToMarkdown command when itemIsReadOnly() returns true for a note about to be converted. Read-only status is derived from Joplin Server sharing/ownership and the sync userId — a note owned by another user (shared notebook) cannot be converted, because conversion duplicates then trashes the original, which would destroy another user's content.","triggerScenarios":"The user selects an HTML note that belongs to a shared folder they do not own (sync.userId !== note owner) and invokes 'Convert to Markdown'. itemIsReadOnly() consults the share service and returns true, so the conversion aborts before Note.duplicate runs.","commonSituations":"Working in a shared Joplin Server notebook where notes are owned by a colleague; the share service reports the note as read-only for the current user; the command's enabledCondition ('!noteIsReadOnly') was bypassed (e.g. multi-select where at least one note is read-only).","solutions":["Ask the notebook owner to convert the note, or to give you write ownership.","Copy the note body out manually into a new Markdown note you own instead of using the convert command.","If you believe you should own the note, verify the share/ownership settings on the Joplin Server.","Avoid running the command on a multi-selection that includes shared notes."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"import { itemIsReadOnly } from './models/utils/readOnly';\nif (await itemIsReadOnly(Note, ModelType.Note, ItemChange.SOURCE_UNSPECIFIED, note.id, Setting.value('sync.userId'), shareService)) {\n  // do not attempt conversion; the command will throw\n  showReadOnlyWarning(note);\n  return;\n}","typeGuard":null,"tryCatchPattern":"try {\n  await commandRuntime.execute({ ... } as CommandContext, noteIds);\n} catch (error) {\n  if (/Cannot convert read-only item/.test(error.message)) {\n    // inform the user the note is shared/read-only\n    return;\n  }\n  throw error;\n}","preventionTips":["Check itemIsReadOnly() before offering the 'Convert to Markdown' action in the UI.","Avoid multi-select conversions that include shared notes you don't own.","Respect the command's enabledCondition ('!noteIsReadOnly') in custom integrations."],"tags":["commands","read-only","sharing","permissions","conversion"],"backgroundTag":null,"analyzedSha":"2654b33620775080d1d59c552259d41e33dad3d2","analyzedAt":"2026-08-12T14:26:46.263Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}