Hmbown/CodeWhale · error · Error
Downloaded release artifact must be a regular file: ${source
Error message
Downloaded release artifact must be a regular file: ${source} What it means
assemble() lstat()ed an expected intermediate artifact and it exists but is not a regular file — a directory, symlink, fifo, or similar. Because lstat does not follow symlinks, a symlink to the real binary is rejected just like a directory. The guard ensures only real bytes are copied into the release.
Source
Thrown at scripts/release/assemble-release-assets.js:135
async function assemble(inputDirectory, outputDirectory) {
const expected = allReleaseAssetNames();
const generated = new Set([WINDOWS_LAUNCHER, CHECKSUM_MANIFEST]);
const copiedNames = expected.filter((name) => !generated.has(name));
const sources = new Map();
for (const name of copiedNames) {
const source = intermediateArtifactPath(inputDirectory, name);
let sourceStat;
try {
sourceStat = await fs.lstat(source);
} catch (error) {
if (error && error.code === "ENOENT") {
throw new Error(`Downloaded release artifacts are missing ${name} at ${source}`);
}
throw error;
}
if (!sourceStat.isFile()) {
throw new Error(`Downloaded release artifact must be a regular file: ${source}`);
}
sources.set(name, source);
}
await fs.mkdir(outputDirectory, { recursive: true });
const existing = await fs.readdir(outputDirectory);
if (existing.length > 0) {
throw new Error(`Output directory must be empty: ${outputDirectory}`);
}
for (const name of copiedNames) {
await fs.copyFile(sources.get(name), path.join(outputDirectory, name));
}
await fs.writeFile(
path.join(outputDirectory, WINDOWS_LAUNCHER),
windowsLauncherContents(),
"utf8",
);View on GitHub (pinned to 8880682c63)
Solutions
- Make the path a real regular file: replace the symlink with its target's bytes (cp -L) or flatten the extra directory level
- Fix the unpack step so each artifact lands as a file at INPUT_DIR/<name>/<name>
- Re-run assemble after correcting the INPUT_DIR layout
Example fix
# before: artifacts/codewhale-x86_64/codewhale-x86_64.tar.gz is a symlink -> rejected # after cp -L artifacts/codewhale-x86_64/codewhale-x86_64.tar.gz /tmp/real.tar.gz mv /tmp/real.tar.gz artifacts/codewhale-x86_64/codewhale-x86_64.tar.gz
Defensive patterns
Strategy: validation
Validate before calling
const fs = require("node:fs/promises");
const path = require("node:path");
async function assertRegularFile(file) {
const stat = await fs.lstat(file); // lstat, like the script: does not follow symlinks
if (!stat.isFile()) throw new Error(`${file} is not a regular file; flatten or copy with cp -L`);
} Prevention
- Disable symlink-based dedupe/caching for artifact directories used as assemble input
- After unpacking, assert each expected path is a file before invoking assemble
- Prefer downloading artifacts over re-extracting archives when possible — downloads preserve file types
When it happens
Trigger: INPUT_DIR/<name>/<name> resolving to a directory because the artifact unpacked with an extra nesting level; artifacts replaced by symlinks from dedup tooling or manual 'save disk' setups; a fifo or socket accidentally created at the path.
Common situations: An unpack/download step creating directories where files are expected; artifact caching layers that dedupe via symlinks; workflow changes altering the artifact layout.
Related errors
- Downloaded release artifacts are missing ${name} at ${source
- ${label} does not match the authoritative inventory; missing
- Release asset directory must be flat; found: ${nonFiles.map(
- Output directory must be empty: ${outputDirectory}
- CODEWHALE_SMOKE_ASSETS_DIR is not a directory: ${releaseAsse
AI-assisted analysis of Hmbown/CodeWhale@8880682c63 (2026-08-16).
Data as JSON: /api/errors/4c7df9ed899e6538.
Report an issue: GitHub.