{"record":{"id":"f6fc261f6df8de0b","repo":"anomalyco/sst","slug":"failed-to-copy-file-s-w","errorCode":null,"errorMessage":"failed to copy file %s: %w","messagePattern":"failed to copy file (.+?): %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/runtime/python/build.go","lineNumber":787,"sourceCode":"\t\t\t\t}\n\t\t\t\tcopied = true\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tif !copied {\n\t\t\t// Handler path fully resolved by workspaceDir — root .py files will be copied below\n\t\t}\n\t}\n\n\t// Also copy root-level .py files\n\tentries, err := os.ReadDir(workspaceDir)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to read workspace directory: %w\", err)\n\t}\n\tfor _, entry := range entries {\n\t\tif !entry.IsDir() && strings.HasSuffix(entry.Name(), \".py\") {\n\t\t\tif err := copyFile(filepath.Join(workspaceDir, entry.Name()), filepath.Join(outputBase, entry.Name())); err != nil {\n\t\t\t\treturn fmt.Errorf(\"failed to copy file %s: %w\", entry.Name(), err)\n\t\t\t}\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// copySyncedDependencies installs dependencies with correct platform targeting\nfunc copySyncedDependencies(ctx context.Context, input *runtime.BuildInput, projectInfo *projectInfo, architecture string) error {\n\trequirementsPath := filepath.Join(input.Out(), \"requirements.txt\")\n\n\tif _, err := os.Stat(requirementsPath); os.IsNotExist(err) {\n\t\tslog.Warn(\"requirements.txt not found, skipping dependency installation\", \"path\", requirementsPath)\n\t\treturn nil\n\t}\n\n\tworkspaceRoot := findWorkspaceRoot(projectInfo)\n","sourceCodeStart":769,"sourceCodeEnd":805,"githubUrl":"https://github.com/anomalyco/sst/blob/a0bd20f762883e72a35caccb4896c42ce5b3f707/pkg/runtime/python/build.go#L769-L805","documentation":"While enumerating root-level .py files in the workspace, copySourceFilesSimple copies each one into the build output with copyFile. This error is returned for a specific .py file that fails to copy; the message names the file and the wrapped OS error gives the cause (unreadable source or unwritable destination).","triggerScenarios":"copyFile(filepath.Join(workspaceDir, entry.Name()), filepath.Join(outputBase, entry.Name())) fails — the .py file is unreadable, the destination exists as a directory, or the output volume is full/read-only.","commonSituations":"A root .py file with restrictive permissions; an output path colliding with a directory of the same name from a prior build; disk quota exceeded on CI; read-only mounted workspace.","solutions":["Fix permissions on the named file: `chmod u+r <file>.py`.","Remove the conflicting directory/file at the destination in the build output (`rm -rf .sst`).","Free disk space if the wrapped error is ENOSPC.","Check the workspace is not mounted read-only and the current user has write access to the output dir."],"exampleFix":"// before\nError: failed to copy source files: failed to copy file utils.py: permission denied\n// after\n$ chmod u+r utils.py\n$ rm -rf .sst\n$ sst deploy","handlingStrategy":"try-catch","validationCode":"for (const f of fs.readdirSync(wsDir).filter(f => f.endsWith('.py'))) {\n  fs.accessSync(path.join(wsDir, f), fs.constants.R_OK);\n  const dest = path.join(buildOut, f);\n  if (fs.existsSync(dest) && fs.statSync(dest).isDirectory()) throw new Error(`dest collision: ${dest}`);\n}","typeGuard":"null","tryCatchPattern":"try {\n  await deploy();\n} catch (e) {\n  if (/failed to copy file \\S+\\.py/.test(e.message)) {\n    fs.chmodSync(e.message.match(/file (\\S+\\.py)/)?.[1] ?? '.', 0o644); // restore readability\n    await deploy();\n  } else throw e;\n}","preventionTips":["Keep root-level .py files readable (0644) and owned by the deploying user","Clean .sst to avoid destination name collisions","Watch CI disk usage; ENOSPC shows up as copy failures","Deploy from writable, non-read-only mounts"],"tags":["filesystem","python","build","copy"],"backgroundTag":"file-copy-failed","analyzedSha":"a0bd20f762883e72a35caccb4896c42ce5b3f707","analyzedAt":"2026-08-30T11:26:00.383Z","schemaVersion":2},"datasetVersion":"2026-08-30T13:17:10.514Z"}