pbakaus/impeccable · error
usage: write <slug-or-target> <body-file>
Error message
usage: write <slug-or-target> <body-file>
What it means
The critique-storage `write` subcommand requires two positional arguments: a slug-or-target and a body file to store. When either is missing or empty (`coerce_slug` returns None or the body-file argument is absent/empty), it prints this usage line and exits 1 without reading or writing anything.
Source
Thrown at crates/context/src/critique_storage.rs:465
"slug" => {
let slug = slug_from_target(rest.first().map(String::as_str), &cwd);
match slug {
Some(s) => {
io.out(&format!("{}\n", s));
0
}
None => {
io.err("no stable slug for input\n");
1
}
}
}
"write" => {
let slug_arg = rest.first().map(String::as_str).unwrap_or("");
let slug = coerce_slug(rest.first().map(String::as_str), &cwd);
let body_file = rest.get(1).filter(|s| !s.is_empty());
let (Some(slug), Some(body_file)) = (slug, body_file) else {
io.err("usage: write <slug-or-target> <body-file>\n");
return 1;
};
let raw = match std::fs::read(body_file) {
Ok(b) => String::from_utf8_lossy(&b).into_owned(),
Err(e) => {
// JS: uncaught exception -> stack trace on stderr, exit 1
io.err(&format!("{}\n", uncaught(&node_read_error(body_file, &e))));
return 1;
}
};
let mut parsed_meta: Map<String, Value> = Map::new();
if let Some(m) = env.get("IMPECCABLE_CRITIQUE_META").filter(|s| !s.is_empty()) {
if let Ok(Value::Object(o)) = serde_json::from_str::<Value>(m) {
parsed_meta = o;
}
}
// JS #660: the helper, not caller metadata, owns the target
// fingerprint/identity. Drop any caller-supplied copies (preservingView on GitHub (pinned to 2bc2879276)
Solutions
- Supply both positionals: `write <slug-or-target> <body-file>`.
- Check shell variables are non-empty before invoking; quote paths.
- Use a slug known to work (test it with the `slug` subcommand first).
- Write the critique body to a file first, then pass its path as the second argument.
Example fix
// before (FILE unset) context critique write my-app-web "$FILE" // usage: write <slug-or-target> <body-file> // after context critique write my-app-web ./critique.md
Defensive patterns
Strategy: validation
Validate before calling
const [slug, bodyFile] = restArgs;
if (!slug?.trim() || !bodyFile?.trim()) {
console.error('usage: write <slug-or-target> <body-file>');
process.exit(2);
}
if (!existsSync(bodyFile)) {
console.error(`body file not found: ${bodyFile}`);
process.exit(2);
} Type guard
function writeArgsValid(rest) {
return typeof rest?.[0] === 'string' && rest[0].trim().length > 0 &&
typeof rest?.[1] === 'string' && rest[1].trim().length > 0;
} Try / catch
const res = spawnSync('context', ['critique', 'write', slug, bodyFile], { encoding: 'utf8' });
if (res.status !== 0 && res.stderr.startsWith('usage: write')) {
console.error('Both a slug-or-target and a body-file are required.');
} Prevention
- Validate shell variables are non-empty before interpolating into the command.
- Write the critique body to a file before invoking write; never rely on an in-flight pipe.
- Pre-test the slug with the `slug` subcommand to confirm coercion works.
When it happens
Trigger: Running `write` with zero or one positional argument; passing an empty string as either argument; the slug argument is present but `coerce_slug` can't derive a stable slug from it (same coercion as the slug subcommand); the body-file argument is an empty string rather than a path.
Common situations: Shell variable expansion yielding empty args (`write "$SLUG" "$FILE"` with unset vars); forgetting the body file when piping output manually; copying usage from an older version of the tool with different argument order.
Understand the failure class
Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.
Related errors
- usage: comp-diff.mjs --comp <png> --build <png> [--spec spec
- usage: comp-spec.mjs --comp <png> (--grid | --regions <json>
- embed-prompt: --scan needs at least one directory
- generate-image: --prompt (or --prompt-file) and --out are re
- surface brief path requires a concrete target
AI-assisted analysis of pbakaus/impeccable@2bc2879276 (2026-09-08).
Data as JSON: /api/errors/0e07fd2e415b8c23.
Report an issue: GitHub.