{"record":{"id":"60f7be45b59e31fa","repo":"anomalyco/sst","slug":"failed-to-read-workspace-directory-w","errorCode":null,"errorMessage":"failed to read workspace directory: %w","messagePattern":"failed to read workspace directory: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/runtime/python/build.go","lineNumber":782,"sourceCode":"\t\t\tcandidate := parts[i]\n\t\t\tcandidatePath := filepath.Join(workspaceDir, candidate)\n\t\t\tif info, err := os.Stat(candidatePath); err == nil && info.IsDir() {\n\t\t\t\tif err := copyDir(candidatePath, filepath.Join(outputBase, candidate), skipContent); err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"failed to copy directory %s: %w\", candidate, err)\n\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)","sourceCodeStart":764,"sourceCodeEnd":800,"githubUrl":"https://github.com/anomalyco/sst/blob/a0bd20f762883e72a35caccb4896c42ce5b3f707/pkg/runtime/python/build.go#L764-L800","documentation":"After copying handler directories, copySourceFilesSimple lists the workspace directory with os.ReadDir to copy root-level .py files into the build output. This error is returned when the workspace directory itself cannot be read. It wraps the OS error (ENOENT, EACCES, ENOTDIR).","triggerScenarios":"os.ReadDir(workspaceDir) fails when projectInfo.SourceRoot / the directory containing pyproject.toml does not exist, was deleted, or is not readable — e.g. a misconfigured pyproject path or a workspace root that is actually a file.","commonSituations":"pyproject.toml moved/renamed so the derived workspace dir no longer exists; running deploy from the wrong working directory; project root renamed without updating config; symlinked workspace pointing to a deleted location.","solutions":["Verify the pyproject.toml / workspace root path exists: `ls <projectRoot>/pyproject.toml`; fix config or restore the directory.","Run `sst deploy` from the app root so projectInfo paths resolve correctly.","Check permissions on the workspace directory (`chmod u+rx <workspaceDir>`).","Clean and regenerate build state: `rm -rf .sst` and redeploy."],"exampleFix":"// before\nError: failed to copy source files: failed to read workspace directory: open /app/packages/api: no such file or directory\n// after\n$ cd /app && ls packages/api/pyproject.toml  # fix path or restore dir\n$ sst deploy","handlingStrategy":"validation","validationCode":"const wsDir = path.dirname(pyprojectPath); // what SST derives\nif (!fs.existsSync(wsDir)) throw new Error(`workspace dir ${wsDir} missing — check pyproject.toml location`);\nfs.accessSync(wsDir, fs.constants.R_OK | fs.constants.X_OK);","typeGuard":"null","tryCatchPattern":"try {\n  await deploy();\n} catch (e) {\n  if (/failed to read workspace directory/.test(e.message)) {\n    console.error('Workspace root missing/unreadable — verify pyproject.toml path and run from app root');\n    throw e;\n  } else throw e;\n}","preventionTips":["Keep pyproject.toml in place; don't rename its directory without updating config","Always run sst from the app/project root","Avoid symlinking the workspace to volatile locations","Verify SourceRoot paths after project restructuring"],"tags":["filesystem","python","build","workspace"],"backgroundTag":"directory-not-found","analyzedSha":"a0bd20f762883e72a35caccb4896c42ce5b3f707","analyzedAt":"2026-08-30T11:26:00.383Z","schemaVersion":2},"datasetVersion":"2026-08-30T13:17:10.514Z"}