{"record":{"id":"e8fdd39f88500df4","repo":"anomalyco/sst","slug":"handler-not-found-s-searched-d-candidate-paths","errorCode":null,"errorMessage":"handler not found: %s (searched %d candidate paths)","messagePattern":"handler not found: (.+?) \\(searched (.+?) candidate paths\\)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/runtime/python/project.go","lineNumber":97,"sourceCode":"\treturn info, nil\n}\n\n// findPythonFile locates the Python file for the given handler path.\nfunc findPythonFile(projectRoot, handlerPath string) (string, error) {\n\tfilePath := extractFilePath(handlerPath)\n\tcandidates := generateCandidatePaths(projectRoot, filePath)\n\n\tfor _, candidate := range candidates {\n\t\tif info, err := os.Stat(candidate); err == nil && info.Mode().IsRegular() && strings.HasSuffix(candidate, \".py\") {\n\t\t\tabsPath, err := filepath.Abs(candidate)\n\t\t\tif err != nil {\n\t\t\t\treturn \"\", fmt.Errorf(\"failed to get absolute path for %s: %w\", candidate, err)\n\t\t\t}\n\t\t\treturn absPath, nil\n\t\t}\n\t}\n\n\treturn \"\", fmt.Errorf(\"handler not found: %s (searched %d candidate paths)\", handlerPath, len(candidates))\n}\n\n// extractFilePath extracts the file path from a handler path.\nfunc extractFilePath(handlerPath string) string {\n\tif lastDot := strings.LastIndex(handlerPath, \".\"); lastDot != -1 {\n\t\treturn handlerPath[:lastDot]\n\t}\n\treturn handlerPath\n}\n\n// generateCandidatePaths creates a list of potential file locations.\nfunc generateCandidatePaths(projectRoot, handlerPath string) []string {\n\tvar candidates []string\n\n\t// Direct path and with .py extension\n\tcandidates = append(candidates, filepath.Join(projectRoot, handlerPath))\n\tif !strings.HasSuffix(handlerPath, \".py\") {\n\t\tcandidates = append(candidates, filepath.Join(projectRoot, handlerPath+\".py\"))","sourceCodeStart":79,"sourceCodeEnd":115,"githubUrl":"https://github.com/anomalyco/sst/blob/a0bd20f762883e72a35caccb4896c42ce5b3f707/pkg/runtime/python/project.go#L79-L115","documentation":"findPythonFile iterates every generated candidate path (project root, plus src/, app/, functions/, lambda/, handlers/, lib/ subdirectories, with and without the .py extension) and throws this when none is a regular .py file. The message reports the handler string and how many candidate paths were searched, aiding diagnosis of where the resolver looked.","triggerScenarios":"resolveHandler was given a handler path like \"src/index.handler\" but no file matching src/index (or src/index.py) exists under the resolved projectRoot; also fires for empty/incorrect handler values that still yield candidates.","commonSituations":"Renamed or deleted the handler file after updating code; handler path includes a leading './' or absolute path the candidate generator doesn't expect; monorepo where the Python app lives in a subdirectory not covered by the candidate list; handler uses underscore/hyphen inconsistently with the file name.","solutions":["Confirm the exact file path (without .handler suffix) exists, e.g. ls <projectRoot>/src/index.py.","Fix the handler field to a path relative to the project root, e.g. \"src/index.handler\".","If the code lives in a non-standard directory, either move it into root/src/ or place a pyproject.toml and align paths.","Check that the deploy root (resolved from cfgPath) is the directory containing your code, not a parent or child."],"exampleFix":"// before\nhandler: \"functions/process.fn\"\n// (no functions/process.py on disk)\n\n// after\nhandler: \"src/process.fn\"  // src/process.py exists","handlingStrategy":"validation","validationCode":"// shell\ntest -f <root>/src/index.py && echo OK || echo \"handler file missing\"\n// generic check: file must exist under root or root/{src,app,functions,lambda,handlers,lib}","typeGuard":null,"tryCatchPattern":"try { await deploy() } catch (e) {\n  if (String(e).includes(\"handler not found:\"))\n    console.error(\"Searched candidate dirs; confirm file exists:\", String(e));\n  throw e;\n}","preventionTips":["Place handlers in standard directories (src/, app/, functions/, lambda/, handlers/, lib/) or the project root.","Match handler path exactly to file path minus the '.handler' suffix.","Never rename handler files without updating the config."],"tags":["python","handler-resolution","file-not-found"],"backgroundTag":"handler-file-not-found","analyzedSha":"a0bd20f762883e72a35caccb4896c42ce5b3f707","analyzedAt":"2026-08-30T11:26:00.383Z","schemaVersion":2},"datasetVersion":"2026-08-30T13:17:10.514Z"}