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

  1. Check `files.length > 0` before calling `copyFilesToFolder` if an empty set is legitimately possible.
  2. Verify the glob/source feeding `files` actually matches entries (log the array).
  3. 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

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


AI-assisted analysis of withastro/astro@d081033d5f (2026-08-12). Data as JSON: /api/errors/c13e1e0331b730c7. Report an issue: GitHub.