{"record":{"id":"e10b37e4d9d818bb","repo":"paperclipai/paperclip","slug":"directory-already-exists-outputdir","errorCode":null,"errorMessage":"Directory already exists: ${outputDir}","messagePattern":"Directory already exists: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/plugins/create-paperclip-plugin/src/index.ts","lineNumber":139,"sourceCode":" * and a local dev server script for hot-reload workflow.\n */\nexport function scaffoldPluginProject(options: ScaffoldPluginOptions): string {\n  const template = options.template ?? \"default\";\n  if (!VALID_TEMPLATES.includes(template)) {\n    throw new Error(`Invalid template '${template}'. Expected one of: ${VALID_TEMPLATES.join(\", \")}`);\n  }\n\n  if (!isValidPluginName(options.pluginName)) {\n    throw new Error(\"Invalid plugin name. Must be lowercase and may include scope, dots, underscores, or hyphens.\");\n  }\n\n  if (options.category && !VALID_CATEGORIES.has(options.category)) {\n    throw new Error(`Invalid category '${options.category}'. Expected one of: ${[...VALID_CATEGORIES].join(\", \")}`);\n  }\n\n  const outputDir = path.resolve(options.outputDir);\n  if (fs.existsSync(outputDir)) {\n    throw new Error(`Directory already exists: ${outputDir}`);\n  }\n\n  const displayName = options.displayName ?? makeDisplayName(options.pluginName);\n  const description = options.description ?? \"A Paperclip plugin\";\n  const author = options.author ?? \"Plugin Author\";\n  const category = options.category ?? (template === \"workspace\" ? \"workspace\" : template === \"environment\" ? \"environment\" : \"connector\");\n  const manifestId = packageToManifestId(options.pluginName);\n  const localSdkPath = path.resolve(options.sdkPath ?? getLocalSdkPackagePath());\n  const localSharedPath = getLocalSharedPackagePath(localSdkPath);\n  const repoRoot = getRepoRootFromSdkPath(localSdkPath);\n  const useWorkspaceSdk = isInsideDir(outputDir, repoRoot);\n\n  fs.mkdirSync(outputDir, { recursive: true });\n\n  const packedSharedTarball = useWorkspaceSdk ? null : packLocalPackage(localSharedPath, outputDir);\n  const sdkDependency = useWorkspaceSdk\n    ? \"workspace:*\"\n    : `file:${toPosixPath(path.relative(outputDir, packLocalPackage(localSdkPath, outputDir)))}`;","sourceCodeStart":121,"sourceCodeEnd":157,"githubUrl":"https://github.com/paperclipai/paperclip/blob/67001ec6eb96ae601aa27bc91d9b2415d665334a/packages/plugins/create-paperclip-plugin/src/index.ts#L121-L157","documentation":"Thrown by scaffoldPluginProject() after resolving options.outputDir to an absolute path, when fs.existsSync() reports that path already exists on disk. The scaffolder refuses to overwrite an existing directory to avoid clobbering an in-progress plugin project. The absolute path is included in the message so the offender is identifiable.","triggerScenarios":"Running the scaffolder twice into the same outputDir. Passing a relative outputDir that resolves (via path.resolve) onto an existing folder under the current cwd. A previous failed run left a partial directory behind.","commonSituations":"Re-running `create-paperclip-plugin` during iteration without cleaning up. Pointing outputDir at a parent of an existing project. CI running on a dirty workspace where the prior attempt's directory survived.","solutions":["Pick a new outputDir, or delete/move the existing directory first (rm -rf <outputDir>).","If the existing dir is a stale partial scaffold from a failed run, remove it before re-running.","Confirm the resolved absolute path printed in the message matches your intent — a relative path may resolve further up the tree than expected."],"exampleFix":"// before\nscaffoldPluginProject({ pluginName: \"@acme/foo\", outputDir: \"./foo\" }); // ./foo already exists\n// after\nfs.rmSync(\"./foo\", { recursive: true, force: true });\nscaffoldPluginProject({ pluginName: \"@acme/foo\", outputDir: \"./foo\" });","handlingStrategy":"validation","validationCode":"import fs from \"node:fs\";\nfunction ensureFreshOutputDir(dir: string): void {\n  if (fs.existsSync(dir)) {\n    throw new Error(`Refusing to scaffold: ${dir} already exists. Remove it first.`);\n  }\n}\n// before calling scaffoldPluginProject:\nensureFreshOutputDir(opts.outputDir);","typeGuard":null,"tryCatchPattern":"try {\n  scaffoldPluginProject(opts);\n} catch (err) {\n  if (err instanceof Error && err.message.startsWith(\"Directory already exists:\")) {\n    // prompt user, then either remove or pick a new dir\n  } else throw err;\n}","preventionTips":["Always scaffold into a fresh directory; clean up failed runs.","In CI, run on a clean checkout or wipe outputDir at the start of the job.","Use path.resolve() in your own check to match the scaffolder's resolution."],"tags":["filesystem","plugin-scaffold","idempotency"],"backgroundTag":null,"analyzedSha":"67001ec6eb96ae601aa27bc91d9b2415d665334a","analyzedAt":"2026-08-12T12:05:45.408Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}