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 (preserving

View on GitHub (pinned to 2bc2879276)

Solutions

  1. Supply both positionals: `write <slug-or-target> <body-file>`.
  2. Check shell variables are non-empty before invoking; quote paths.
  3. Use a slug known to work (test it with the `slug` subcommand first).
  4. 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

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


AI-assisted analysis of pbakaus/impeccable@2bc2879276 (2026-09-08). Data as JSON: /api/errors/0e07fd2e415b8c23. Report an issue: GitHub.