paperclipai/paperclip · error · Error
Directory already exists: ${outputDir}
Error message
Directory already exists: ${outputDir} What it means
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.
Source
Thrown at packages/plugins/create-paperclip-plugin/src/index.ts:139
* and a local dev server script for hot-reload workflow.
*/
export function scaffoldPluginProject(options: ScaffoldPluginOptions): string {
const template = options.template ?? "default";
if (!VALID_TEMPLATES.includes(template)) {
throw new Error(`Invalid template '${template}'. Expected one of: ${VALID_TEMPLATES.join(", ")}`);
}
if (!isValidPluginName(options.pluginName)) {
throw new Error("Invalid plugin name. Must be lowercase and may include scope, dots, underscores, or hyphens.");
}
if (options.category && !VALID_CATEGORIES.has(options.category)) {
throw new Error(`Invalid category '${options.category}'. Expected one of: ${[...VALID_CATEGORIES].join(", ")}`);
}
const outputDir = path.resolve(options.outputDir);
if (fs.existsSync(outputDir)) {
throw new Error(`Directory already exists: ${outputDir}`);
}
const displayName = options.displayName ?? makeDisplayName(options.pluginName);
const description = options.description ?? "A Paperclip plugin";
const author = options.author ?? "Plugin Author";
const category = options.category ?? (template === "workspace" ? "workspace" : template === "environment" ? "environment" : "connector");
const manifestId = packageToManifestId(options.pluginName);
const localSdkPath = path.resolve(options.sdkPath ?? getLocalSdkPackagePath());
const localSharedPath = getLocalSharedPackagePath(localSdkPath);
const repoRoot = getRepoRootFromSdkPath(localSdkPath);
const useWorkspaceSdk = isInsideDir(outputDir, repoRoot);
fs.mkdirSync(outputDir, { recursive: true });
const packedSharedTarball = useWorkspaceSdk ? null : packLocalPackage(localSharedPath, outputDir);
const sdkDependency = useWorkspaceSdk
? "workspace:*"
: `file:${toPosixPath(path.relative(outputDir, packLocalPackage(localSdkPath, outputDir)))}`;View on GitHub (pinned to 67001ec6eb)
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.
Example fix
// before
scaffoldPluginProject({ pluginName: "@acme/foo", outputDir: "./foo" }); // ./foo already exists
// after
fs.rmSync("./foo", { recursive: true, force: true });
scaffoldPluginProject({ pluginName: "@acme/foo", outputDir: "./foo" }); Defensive patterns
Strategy: validation
Validate before calling
import fs from "node:fs";
function ensureFreshOutputDir(dir: string): void {
if (fs.existsSync(dir)) {
throw new Error(`Refusing to scaffold: ${dir} already exists. Remove it first.`);
}
}
// before calling scaffoldPluginProject:
ensureFreshOutputDir(opts.outputDir); Try / catch
try {
scaffoldPluginProject(opts);
} catch (err) {
if (err instanceof Error && err.message.startsWith("Directory already exists:")) {
// prompt user, then either remove or pick a new dir
} else throw err;
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Could not locate local Paperclip skills directory. Expected
- This exact package was already imported by a completed trans
- Export output path ${root} exists and is not a directory.
- Export output directory ${root} already contains files. Re-r
- Output path already exists and is not a directory: ${outputD
AI-assisted analysis of paperclipai/paperclip@67001ec6eb (2026-08-12).
Data as JSON: /api/errors/e10b37e4d9d818bb.
Report an issue: GitHub.