{"record":{"id":"3a5596686ffe9b48","repo":"laurent22/joplin","slug":"note-not-published-s","errorCode":null,"errorMessage":"Note not published: %s","messagePattern":"Note not published: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/app-cli/app/command-unpublish.ts","lineNumber":35,"sourceCode":"\nclass Command extends BaseCommand {\n\tpublic usage() {\n\t\treturn 'unpublish [note]';\n\t}\n\n\tpublic description() {\n\t\treturn _('Unpublishes a note from Joplin Server or Joplin Cloud');\n\t}\n\n\tpublic enabled() {\n\t\treturn SyncTargetRegistry.isJoplinServerOrCloud(Setting.value('sync.target'));\n\t}\n\n\tpublic async action(args: Args) {\n\t\tconst targetNote = await app().loadItemOrFail(ModelType.Note, args.note);\n\n\t\tif (!targetNote.is_shared) {\n\t\t\tthrow new Error(_('Note not published: %s', targetNote.title));\n\t\t}\n\n\t\tlogger.info('Unshare note: ', targetNote.id);\n\t\tawait ShareService.instance().unshareNote(targetNote.id);\n\n\t\tconst note = await Note.load(targetNote.id);\n\t\tif (note.is_shared) {\n\t\t\tthrow new Error('Assertion failure: The note is still shared.');\n\t\t}\n\n\t\tthis.stdout(_('Synchronising...'));\n\t\tawait reg.waitForSyncFinishedThenSync();\n\t}\n}\n\nmodule.exports = Command;\n","sourceCodeStart":17,"sourceCodeEnd":52,"githubUrl":"https://github.com/laurent22/joplin/blob/2654b33620775080d1d59c552259d41e33dad3d2/packages/app-cli/app/command-unpublish.ts#L17-L52","documentation":"Thrown by the `unpublish` CLI command when the resolved note has `is_shared` set to false. The command first loads the note via loadItemOrFail (so the note exists), then guards on is_shared before calling ShareService.unshareNote — unpublishing something that was never published (or already unpublished) is rejected.","triggerScenarios":"Calling the unpublish command on a note whose is_shared flag is false. This happens if the note was already unpublished, was never published to Joplin Server/Cloud, or the local sync state is stale and reflects a server-side unpublish.","commonSituations":"Running unpublish twice in a row; the share was removed from another client and the local DB is ahead; the note was shared by a different user and this client only has read access; connecting to a sync target that is not Joplin Server/Cloud (the command is disabled then, but a direct call bypasses enabled()).","solutions":["Sync first (`sync`) so the local is_shared flag matches the server, then retry only if still shared.","Check the note's share status before calling: load it and inspect is_shared.","Confirm the sync target is Joplin Server or Joplin Cloud via `config sync.target`.","If already unpublished, treat as success (no-op) rather than an error."],"exampleFix":"// before\nif (!targetNote.is_shared) {\n  throw new Error(_('Note not published: %s', targetNote.title));\n}\n\n// after — idempotent: skip if already unpublished\nif (!targetNote.is_shared) {\n  this.stdout(_('Note is already unpublished: %s', targetNote.title));\n  return;\n}","handlingStrategy":"validation","validationCode":"const note = await Note.load(noteId);\nif (!note || !note.is_shared) {\n  // nothing to unpublish — skip\n  return;\n}\nawait command.exec(['unpublish', noteId]);","typeGuard":"function isPublished(note: NoteEntity | null): note is NoteEntity & { is_shared: true } {\n  return !!note && note.is_shared === true;\n}","tryCatchPattern":"try {\n  await command.exec(['unpublish', noteId]);\n} catch (e) {\n  if (e.message.startsWith('Note not published')) {\n    // already unpublished — treat as success\n  } else throw e;\n}","preventionTips":["Check note.is_shared before calling unpublish to make the operation idempotent.","Sync before unpublish so the local flag reflects server state.","Confirm the sync target is Joplin Server/Cloud (the command is disabled otherwise)."],"tags":["cli","sharing","joplin-server","validation"],"backgroundTag":null,"analyzedSha":"2654b33620775080d1d59c552259d41e33dad3d2","analyzedAt":"2026-08-12T14:26:46.263Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}