jackwener/OpenCLI · error
Directory "${targetDir}" already exists and is not empty.
Error message
Directory "${targetDir}" already exists and is not empty. What it means
createPluginScaffold resolves the target directory (opts.dir or the plugin name) and refuses to proceed if it already exists and is non-empty, to avoid clobbering existing files. An empty existing directory is allowed and simply reused; a non-empty one throws this Error before any files are written.
Source
Thrown at src/plugin-scaffold.ts:49
/**
* Create a new plugin scaffold directory.
*/
export function createPluginScaffold(name: string, opts: ScaffoldOptions = {}): ScaffoldResult {
// Validate name
if (!/^[a-z][a-z0-9-]*$/.test(name)) {
throw new Error(
`Invalid plugin name "${name}". ` +
`Plugin names must start with a lowercase letter and contain only lowercase letters, digits, and hyphens.`
);
}
const targetDir = opts.dir
? path.resolve(opts.dir)
: path.resolve(name);
if (fs.existsSync(targetDir) && fs.readdirSync(targetDir).length > 0) {
throw new Error(`Directory "${targetDir}" already exists and is not empty.`);
}
fs.mkdirSync(targetDir, { recursive: true });
const files: string[] = [];
// opencli-plugin.json
const manifest = {
name,
version: '0.1.0',
description: opts.description ?? `An opencli plugin: ${name}`,
opencli: `>=${PKG_VERSION}`,
};
writeFile(targetDir, 'opencli-plugin.json', JSON.stringify(manifest, null, 2) + '\n');
files.push('opencli-plugin.json');
// package.json
const pkg = {View on GitHub (pinned to 49907e53dc)
Solutions
- Delete or move the existing directory, then rerun the scaffold
- Pass a different opts.dir (or plugin name) pointing at a fresh path
- If reuse is intended, empty the directory first — an existing but empty directory is accepted
Example fix
// before
createPluginScaffold('my-plugin'); // second run, dir already populated
// after
rm -rf ./my-plugin && createPluginScaffold('my-plugin');
// or target a fresh location
createPluginScaffold('my-plugin', { dir: './plugins/my-plugin-v2' }); Defensive patterns
Strategy: validation
Validate before calling
import fs from 'fs'; import path from 'path';
const targetDir = opts.dir ? path.resolve(opts.dir) : path.resolve(name);
if (fs.existsSync(targetDir) && fs.readdirSync(targetDir).length > 0) {
throw new Error(`target not empty: ${targetDir}`);
} Type guard
function isWritableFreshDir(dir: string): boolean {
return !fs.existsSync(dir) || fs.readdirSync(dir).length === 0;
} Try / catch
try {
createPluginScaffold(name, opts);
} catch (e) {
if (e instanceof Error && e.message.includes('already exists and is not empty')) {
console.error('Pick a new --dir or remove/relocate the existing directory.');
} else throw e;
} Prevention
- Check the target directory with fs.existsSync/readdirSync before scaffolding
- Use unique per-plugin directories (e.g. plugins/<name>) to avoid collisions
- Clean up failed scaffold attempts before rerunning
- Never point opts.dir at a populated folder like the repo root
When it happens
Trigger: Running the scaffold twice for the same plugin name without deleting the first output, or pointing opts.dir at an existing populated directory such as the current repo folder.
Common situations: Re-running a failed/partial scaffold after a first attempt partially populated the directory, choosing the project root as opts.dir, leftover files from a previous experiment with the same plugin name.
Related errors
- Invalid plugin name "${name}". Plugin names must start with
- Local plugin path is not a directory: ${localPath}
- Video file not found: ${filePath}
- Video file is empty: ${filePath}
- 封面文件不存在: ${path.resolve(coverPath)}
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/83af4e100d6667b3.
Report an issue: GitHub.