withastro/astro · error · Error
No files found to copy
Error message
No files found to copy
What it means
Thrown by `copyFilesToDummy`/`copyFilesToFolder` in @astrojs/internal-helpers when the `files` array passed in is empty. The function computes a common ancestor and copies each file; with zero files it cannot proceed (and `fileList[0]` would be undefined).
Source
Thrown at packages/internal-helpers/src/fs.ts:51
/**
* Copies files into a folder keeping the folder structure intact.
* The resulting file tree will start at the common ancestor.
*
* @param {URL[]} files A list of files to copy (absolute path).
* @param {URL} outDir Destination folder where to copy the files to (absolute path).
* @param {URL[]} [exclude] A list of files to exclude (absolute path).
* @returns {Promise<string>} The common ancestor of the copied files.
*/
export async function copyFilesToFolder(
files: URL[],
outDir: URL,
exclude: URL[] = [],
): Promise<string> {
const excludeList = exclude.map((url) => fileURLToPath(url));
const fileList = files.map((url) => fileURLToPath(url)).filter((f) => !excludeList.includes(f));
if (files.length === 0) throw new Error('No files found to copy');
let commonAncestor = nodePath.dirname(fileList[0]);
for (const file of fileList.slice(1)) {
while (!file.startsWith(commonAncestor)) {
commonAncestor = nodePath.dirname(commonAncestor);
}
}
for (const origin of fileList) {
const dest = new URL(nodePath.relative(commonAncestor, origin), outDir);
const realpath = await fs.realpath(origin);
const isSymlink = realpath !== origin;
const isDir = (await fs.stat(origin)).isDirectory();
// Create directories recursively
if (isDir && !isSymlink) {
await fs.mkdir(new URL('..', dest), { recursive: true });View on GitHub (pinned to d081033d5f)
Solutions
- Check `files.length > 0` before calling `copyFilesToFolder` if an empty set is legitimately possible.
- Verify the glob/source feeding `files` actually matches entries (log the array).
- Loosen the `exclude` list if it is filtering out everything.
Example fix
// before
copyFilesToFolder(matchedFiles, outDir, exclude);
// after
if (matchedFiles.length > 0) {
await copyFilesToFolder(matchedFiles, outDir, exclude);
} else {
logger.warn('No files to copy; skipping.');
} Defensive patterns
Strategy: validation
Validate before calling
if (!Array.isArray(files) || files.length === 0) {
throw new Error('No files to copy; check the source glob.');
} Type guard
function isNonEmptyFileList(files: unknown): files is URL[] {
return Array.isArray(files) && files.length > 0;
} Prevention
- Guard callers with a length check when an empty set is valid.
- Log the resolved file list before copying for debuggability.
- Verify exclude patterns don't over-filter.
When it happens
Trigger: Passing an empty array, or an array where every entry was filtered out by the `exclude` list. A glob/build step that produced no matching files for a stage that copies assets.
Common situations: A `public/` or asset directory that is empty in the current build. An integration's file-collection hook returning `[]`. Overly broad `exclude` removing all candidates.
Related errors
- SVG file does not contain an <svg> element
- NoImageMetadata
- FailedToFetchRemoteImageDimensions
- ImageNotFound
- Invalid route ${file} — parameter name must match /^[a-zA-Z0
AI-assisted analysis of withastro/astro@d081033d5f (2026-08-12).
Data as JSON: /api/errors/c13e1e0331b730c7.
Report an issue: GitHub.