{"record":{"id":"9b505fb755b71589","repo":"paperclipai/paperclip","slug":"use-either-apply-or-dry-not-both","errorCode":null,"errorMessage":"Use either --apply or --dry, not both.","messagePattern":"Use either --apply or --dry, not both\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"cli/src/commands/worktree.ts","lineNumber":3292,"sourceCode":"\n    return {\n      insertedProjects,\n      insertedProjectWorkspaces,\n      insertedIssues,\n      insertedComments,\n      insertedDocuments,\n      mergedDocuments,\n      insertedDocumentRevisions,\n      insertedAttachments,\n      skippedMissingAttachmentObjects,\n      insertedIssueIdentifiers,\n    };\n  });\n}\n\nexport async function worktreeMergeHistoryCommand(sourceArg: string | undefined, opts: WorktreeMergeHistoryOptions): Promise<void> {\n  if (opts.apply && opts.dry) {\n    throw new Error(\"Use either --apply or --dry, not both.\");\n  }\n\n  if (sourceArg && opts.from) {\n    throw new Error(\"Use either the positional source argument or --from, not both.\");\n  }\n\n  const targetEndpoint = opts.to\n    ? resolveWorktreeEndpointFromSelector(opts.to, { allowCurrent: true })\n    : resolveCurrentWorktreeEndpoint();\n  const sourceEndpoint = opts.from\n    ? resolveWorktreeEndpointFromSelector(opts.from, { allowCurrent: true })\n    : sourceArg\n      ? resolveWorktreeEndpointFromSelector(sourceArg, { allowCurrent: true })\n      : await promptForSourceEndpoint(targetEndpoint.rootPath);\n\n  if (path.resolve(sourceEndpoint.configPath) === path.resolve(targetEndpoint.configPath)) {\n    throw new Error(\"Source and target Paperclip configs are the same. Choose different --from/--to worktrees.\");\n  }","sourceCodeStart":3274,"sourceCodeEnd":3310,"githubUrl":"https://github.com/paperclipai/paperclip/blob/67001ec6eb96ae601aa27bc91d9b2415d665334a/cli/src/commands/worktree.ts#L3274-L3310","documentation":"Thrown at the top of worktreeMergeHistoryCommand when both --apply and --dry are set. These flags are mutually exclusive because --apply performs the import and --dry explicitly means preview-only; the default (neither flag) is already preview-only, so specifying both is contradictory intent. The guard fails fast before any worktree resolution.","triggerScenarios":"Calling `paperclipai worktree:merge-history --apply --dry ...`.","commonSituations":"A developer copies a previous command, adds --apply, and forgets to remove --dry. Or a wrapper script toggles both flags from environment variables without an exclusive-or check.","solutions":["Drop --dry if you want to import: `paperclipai worktree:merge-history --apply`.","Drop --apply if you only want a preview: `paperclipai worktree:merge-history --dry` (or neither, since preview is the default)."],"exampleFix":"// before\npaperclipai worktree:merge-history --from feature-x --apply --dry\n// after\npaperclipai worktree:merge-history --from feature-x --apply --yes","handlingStrategy":"validation","validationCode":"function validateMergeFlags(opts: { apply?: boolean; dry?: boolean }): void {\n  if (opts.apply && opts.dry) {\n    throw new Error(\"Use either --apply or --dry, not both.\");\n  }\n}\n\n// validate before constructing the full argv / calling the command:\nvalidateMergeFlags({ apply: process.env.APPLY === \"1\", dry: process.env.DRY === \"1\" });","typeGuard":null,"tryCatchPattern":null,"preventionTips":["When deriving flags from env vars, use an explicit precedence (e.g. dry wins only if apply is unset) rather than independent toggles.","In wrapper scripts, assert mutual exclusivity before forwarding argv to the CLI.","Remember that neither flag (preview-only) is the default, so you rarely need --dry at all."],"tags":["worktree","cli","merge","argument-validation"],"backgroundTag":null,"analyzedSha":"67001ec6eb96ae601aa27bc91d9b2415d665334a","analyzedAt":"2026-08-12T12:05:45.408Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}