apache/answer · error
failed to open source file %s: %w
Error message
failed to open source file %s: %w
What it means
This error is wrapped and returned by the embedded-FS copy helper in internal/cli/build.go when sourceFs.Open(srcPath) fails while walking the source tree during a build/copy operation. The source filesystem is typically an embed.FS, so files were compiled into the binary, but the joined path (sourceDir + walked path) does not resolve inside that FS — usually a path-joining bug rather than a missing file on disk. The underlying OS/FS error is preserved via %w.
Source
Thrown at internal/cli/build.go:536
// Construct the absolute path for the source file/directory
srcPath := filepath.Join(sourceDir, path)
srcPath = filepath.ToSlash(srcPath)
// Construct the absolute path for the destination file/directory
dstPath := filepath.Join(targetDir, path)
if d.IsDir() {
// Create the directory in the destination
err := os.MkdirAll(dstPath, os.ModePerm)
if err != nil {
return fmt.Errorf("failed to create directory %s: %w", dstPath, err)
}
} else {
// Open the source file
srcFile, err := sourceFs.Open(srcPath)
if err != nil {
return fmt.Errorf("failed to open source file %s: %w", srcPath, err)
}
defer srcFile.Close()
// Create the destination file
dstFile, err := os.Create(dstPath)
if err != nil {
return fmt.Errorf("failed to create destination file %s: %w", dstPath, err)
}
defer dstFile.Close()
// Copy the file contents
_, err = io.Copy(dstFile, srcFile)
if err != nil {
return fmt.Errorf("failed to copy file contents from %s to %s: %w", srcPath, dstPath, err)
}
}
return nilView on GitHub (pinned to 3b9f137061)
Solutions
- Check the wrapped underlying error in the message to see whether it's ENOENT, ENOTDIR, or invalid path
- Verify sourceDir matches the embed.FS root exactly (no leading './' or duplicate slashes) before calling the copy helper
- Apply filepath.ToSlash to sourceDir itself before filepath.Join, and re-check the constructed srcPath
- If using os.DirFS, confirm the file actually exists on disk and is readable by the build process user
Example fix
// before srcPath := filepath.Join(sourceDir, path) // after srcPath := filepath.ToSlash(filepath.Join(filepath.ToSlash(sourceDir), path))
Defensive patterns
Strategy: validation
Validate before calling
// before invoking the copy/build operation
if _, err := fs.Stat(sourceFs, filepath.ToSlash(sourceDir)); err != nil {
return fmt.Errorf("source dir %q not found in source FS: %w", sourceDir, err)
} Try / catch
if err := copyDir(sourceFs, sourceDir, targetDir); err != nil {
var perr *fs.PathError
if errors.As(err, &perr) {
log.Printf("copy failed on path %s: %v", perr.Path, perr.Err)
}
return err
} Prevention
- Normalize sourceDir with filepath.ToSlash and strip leading './' before joining with walked paths
- Verify the embed directive covers all files you intend to copy
- Test the copy helper on both linux and windows builds to catch separator bugs
When it happens
Trigger: fs.WalkDir over an embed.FS yields a path that, after filepath.Join(sourceDir, path) and filepath.ToSlash, does not exist in the source filesystem; e.g. double slashes, a wrong sourceDir prefix, or opening a path that WalkDir reported but Open cannot resolve (symlinks, case mismatch, Windows backslash leakage).
Common situations: Build-time asset copying where sourceDir was configured with a leading/trailing slash mismatch against the embed directive; cross-platform builds where path separators were not normalized; renamed or moved embedded directories after upgrading the codebase.
Understand the failure class
Background: "open() failed", "failed to open file", "cannot create file" — what a file open error means and how to fix it — this error's family across 42 libraries.
Related errors
- failed to create destination file %s: %w
- failed to clone %s@%s: %w Tip: set ANSWER_MODULE to a local
- failed to run go list: %w
- failed to copy ui files: %w
- failed to read plugins dir: %w
AI-assisted analysis of apache/answer@3b9f137061 (2026-09-05).
Data as JSON: /api/errors/cf5341869f640477.
Report an issue: GitHub.