{"record":{"id":"4c7df9ed899e6538","repo":"Hmbown/CodeWhale","slug":"downloaded-release-artifact-must-be-a-regular-file-source","errorCode":null,"errorMessage":"Downloaded release artifact must be a regular file: ${source}","messagePattern":"Downloaded release artifact must be a regular file: (.+?)","errorType":"console","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"scripts/release/assemble-release-assets.js","lineNumber":135,"sourceCode":"\nasync function assemble(inputDirectory, outputDirectory) {\n  const expected = allReleaseAssetNames();\n  const generated = new Set([WINDOWS_LAUNCHER, CHECKSUM_MANIFEST]);\n  const copiedNames = expected.filter((name) => !generated.has(name));\n  const sources = new Map();\n  for (const name of copiedNames) {\n    const source = intermediateArtifactPath(inputDirectory, name);\n    let sourceStat;\n    try {\n      sourceStat = await fs.lstat(source);\n    } catch (error) {\n      if (error && error.code === \"ENOENT\") {\n        throw new Error(`Downloaded release artifacts are missing ${name} at ${source}`);\n      }\n      throw error;\n    }\n    if (!sourceStat.isFile()) {\n      throw new Error(`Downloaded release artifact must be a regular file: ${source}`);\n    }\n    sources.set(name, source);\n  }\n\n  await fs.mkdir(outputDirectory, { recursive: true });\n  const existing = await fs.readdir(outputDirectory);\n  if (existing.length > 0) {\n    throw new Error(`Output directory must be empty: ${outputDirectory}`);\n  }\n\n  for (const name of copiedNames) {\n    await fs.copyFile(sources.get(name), path.join(outputDirectory, name));\n  }\n  await fs.writeFile(\n    path.join(outputDirectory, WINDOWS_LAUNCHER),\n    windowsLauncherContents(),\n    \"utf8\",\n  );","sourceCodeStart":117,"sourceCodeEnd":153,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/433685b2024e7bc4c99e1e2e326bcad39b4d9d65/scripts/release/assemble-release-assets.js#L117-L153","documentation":"assemble lstat()s each expected intermediate artifact and, after confirming it exists, checks that it is a regular file. Directories, symlinks, sockets, or other special files at the expected path throw this Error naming the path.","triggerScenarios":"A path where an asset file is expected actually contains a directory or symlink, e.g. the downloader created a folder named like the asset, or a symlink from an unpack step.","commonSituations":"Download tooling writing to a directory of the same name, or a misconfigured artifact extraction leaving symlinks instead of files.","solutions":["Inspect the reported path; remove the non-file entry and place the real asset file there.","Replace symlinks with actual file copies before running assemble.","Fix the download step so it writes regular files with the exact expected asset names."],"exampleFix":"// before\napp.zip -> /cache/partial/  (symlink)\n// after\ncp /cache/downloads/app.zip assets/app.zip","handlingStrategy":"validation","validationCode":"for (const name of allReleaseAssetNames()) {\n  const st = await fs.lstat(path.join(inputDir, name));\n  if (!st.isFile()) throw new Error(`${name} is not a regular file`);\n}","typeGuard":null,"tryCatchPattern":"try { await assemble(...); } catch (e) { if (String(e.message).startsWith('Downloaded release artifact must be a regular file')) { console.error('Replace the non-file entry:', e.message); process.exitCode = 1; } else throw e; }","preventionTips":["Ensure the downloader writes regular files with exact asset names.","Avoid naming download directories after asset filenames.","Copy over symlinks before assembly."],"tags":["release","filesystem","validation"],"backgroundTag":"incompatible-source-type","analyzedSha":"433685b2024e7bc4c99e1e2e326bcad39b4d9d65","analyzedAt":"2026-09-15T12:24:24.634Z","contentChangedAt":"2026-09-15T12:24:24.634Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}