jackwener/OpenCLI · error · ArgumentError
output must be a directory path
Error message
output must be a directory path
What it means
normalizePixivOutputRoot validates the --output option before any download is written. It throws ArgumentError('output must be a directory path') when the output value is supplied but is not a string (e.g. a number, boolean, or object was passed). The library only accepts a directory path string for output.
Source
Thrown at clis/pixiv/novel-download-utils.js:60
wordCount,
bookmarkCount,
};
}
export function normalizeNovelFileFormat(value) {
if (value !== undefined && typeof value !== 'string') {
throw new ArgumentError('Novel download format must be txt or md');
}
const format = (value ?? 'txt').toLowerCase();
if (format !== 'txt' && format !== 'md') {
throw new ArgumentError(`Unsupported novel download format: ${format}. Supported formats: txt, md.`);
}
return format;
}
export function normalizePixivOutputRoot(value, fallback) {
if (value !== undefined && typeof value !== 'string') {
throw new ArgumentError('output must be a directory path');
}
const raw = value ?? fallback;
if (!raw || raw.includes('\0')) {
throw new ArgumentError('output must be a non-empty directory path');
}
const resolved = path.resolve(raw);
let ancestor = resolved;
const missingParts = [];
let ancestorStat;
while (!ancestorStat) {
try {
ancestorStat = fs.lstatSync(ancestor);
} catch (error) {
if (error?.code !== 'ENOENT') {
throw new ArgumentError(`output path is not a safe directory: ${ancestor}`);
}
const parent = path.dirname(ancestor);
if (parent === ancestor) {View on GitHub (pinned to 49907e53dc)
Solutions
- Pass a string directory path, e.g. output: './pixiv-downloads/novels'.
- Quote numeric-looking paths in config files (output: "2024") so YAML/JSON does not coerce them to numbers.
- Coerce with String(value) before calling, or omit the argument entirely to use the built-in fallback ('./pixiv-downloads/novels').
Example fix
// before
await downloadNovel(id, { output: 2024 });
// after
await downloadNovel(id, { output: String(config.output ?? './pixiv-downloads/novels') }); Defensive patterns
Strategy: type-guard
Validate before calling
if (output !== undefined && typeof output !== 'string') {
throw new TypeError('output must be a string directory path');
} Type guard
function isDirectoryPath(v) {
return v === undefined || (typeof v === 'string' && v.length > 0);
} Try / catch
try {
await downloadNovel(id, { output });
} catch (e) {
if (e.name === 'ArgumentError' && /output must be a directory path/.test(e.message)) {
output = String(output);
} else throw e;
} Prevention
- Quote numeric-looking path values in YAML/JSON config files.
- Coerce CLI/env inputs with String() before passing path options.
- Type-check option objects with a schema (zod/ajv) at the CLI boundary.
When it happens
Trigger: Calling normalizePixivOutputRoot (directly or via outputRoot/outputDir/output) with a defined non-string value such as normalizePixivOutputRoot(123), normalizePixivOutputRoot(true), or a parsed config object where a string path was expected.
Common situations: Programmatic use of the CLI API passing a numeric or boolean option; YAML/JSON config that parses --output: 2024 (a number) instead of quoting it; a script variable holding null-coalesced value of wrong type.
Understand the failure class
Background: Invalid argument type errors: "must be of type string", "expected X, got Y", and ERR_INVALID_ARG_TYPE explained — this error's family across 15 libraries.
Related errors
- ${label} must be a positive integer
- File not found: ${path}
- File must be a readable text file: ${path}
- ${label} must be an integer between ${min} and ${max}, got $
- 视频文件不存在: ${videoPath}
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/19cbdaa3e0c8e5f7.
Report an issue: GitHub.