Hmbown/CodeWhale · error · Error

CODEWHALE_SMOKE_ASSETS_DIR is not a directory

Error message

CODEWHALE_SMOKE_ASSETS_DIR is not a directory: ${releaseAssetsDir}

What it means

main() in the npm wrapper smoke script accepts a preassembled release-assets directory via CODEWHALE_SMOKE_ASSETS_DIR. If the variable is set but the path is not a directory, the script aborts rather than silently building assets.

Solutions

  1. Set CODEWHALE_SMOKE_ASSETS_DIR to the directory containing the preassembled release assets, not a file.
  2. Verify the path exists with `ls -d "$CODEWHALE_SMOKE_ASSETS_DIR"` before running the smoke script.
  3. Unset the variable to let the script assemble assets itself via the prepare script.

Example fix

// before
export CODEWHALE_SMOKE_ASSETS_DIR=target/release/codewhale.tar.gz
// after
export CODEWHALE_SMOKE_ASSETS_DIR=target/release-assets
Defensive patterns

Strategy: validation

Validate before calling

const dir = process.env.CODEWHALE_SMOKE_ASSETS_DIR;
if (dir) {
  const st = await fsp.stat(dir);
  if (!st.isDirectory()) throw new Error(`not a directory: ${dir}`);
}

Try / catch

try {
  await main();
} catch (err) {
  if (String(err.message).includes("CODEWHALE_SMOKE_ASSETS_DIR")) {
    console.error("Check the assets dir path; it must be a directory, not a file.");
  }
  process.exitCode = 1;
}

Prevention

When it happens

Trigger: CODEWHALE_SMOKE_ASSETS_DIR points to a file, a nonexistent path caught earlier as a stat error, or an empty string that survives the truthiness check via whitespace, and fsp.stat confirms it is not a directory.

Common situations: Typo in the path in CI secrets; pointing the variable at the tarball file instead of the directory of release assets; leftover path from a previous checkout layout.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@433685b202 (2026-09-15). Data as JSON: /api/errors/5fd424e36dd332c4. Report an issue: GitHub.

Appendix: source

Thrown at scripts/release/npm-wrapper-smoke.js:172

  ).trim();
  const releaseAssetsDir = suppliedAssetsDir
    ? path.resolve(suppliedAssetsDir)
    : path.join(tempRoot, "release-assets");
  const packDir = path.join(tempRoot, "pack");
  const installDir = path.join(tempRoot, "install");
  let keepTemp =
    process.env.CODEWHALE_KEEP_SMOKE_DIR === "1" ||
    process.env.DEEPSEEK_TUI_KEEP_SMOKE_DIR === "1";
  let server;

  try {
    await fsp.mkdir(packDir, { recursive: true });
    await fsp.mkdir(installDir, { recursive: true });

    if (suppliedAssetsDir) {
      const assetDirectoryStat = await fsp.stat(releaseAssetsDir);
      if (!assetDirectoryStat.isDirectory()) {
        throw new Error(`CODEWHALE_SMOKE_ASSETS_DIR is not a directory: ${releaseAssetsDir}`);
      }
      console.log(`Using preassembled release assets from ${releaseAssetsDir}`);
    } else {
      const prepareArgs = [prepareAssetsScript, releaseAssetsDir];
      const cargoTargetDir = String(process.env.CARGO_TARGET_DIR || "").trim();
      if (cargoTargetDir) {
        prepareArgs.push(
          path.join(path.resolve(repoRoot, cargoTargetDir), "release"),
        );
      }
      await runCommand(process.execPath, prepareArgs);
    }
    const served = await serveDirectory(releaseAssetsDir);
    server = served.server;

    const env = {
      CODEWHALE_FORCE_DOWNLOAD: "1",
      CODEWHALE_RELEASE_BASE_URL: served.baseUrl,

View on GitHub (pinned to 433685b202)