anomalyco/sst · error

failed to find Python file for handler %s: %w

Error message

failed to find Python file for handler %s: %w

What it means

resolveHandler wraps any failure from findPythonFile (the underlying candidate-path search) into "failed to find Python file for handler %s". It is thrown while resolving the function's handler entry (e.g. "src/api.handler") to an actual .py file on disk during build. The %w chain preserves the underlying reason (abs-path failure or 'handler not found').

Source

Thrown at pkg/runtime/python/project.go:67

				} `toml:"targets"`
			} `toml:"build"`
		} `toml:"hatch"`

		Setuptools struct {
			Packages struct {
				Find struct {
					Where []string `toml:"where"`
				} `toml:"find"`
			} `toml:"packages"`
		} `toml:"setuptools"`
	} `toml:"tool"`
}

// resolveHandler finds and resolves a Python handler.
func resolveHandler(projectRoot, handlerPath string) (*projectInfo, error) {
	handlerFile, err := findPythonFile(projectRoot, handlerPath)
	if err != nil {
		return nil, fmt.Errorf("failed to find Python file for handler %s: %w", handlerPath, err)
	}

	pyprojectPath, _ := findPyprojectToml(projectRoot, handlerFile)

	info := &projectInfo{
		ProjectRoot:   projectRoot,
		PyprojectPath: pyprojectPath,
	}

	info.SourceRoot = resolveSourceRoot(projectRoot, pyprojectPath)

	return info, nil
}

// findPythonFile locates the Python file for the given handler path.
func findPythonFile(projectRoot, handlerPath string) (string, error) {
	filePath := extractFilePath(handlerPath)
	candidates := generateCandidatePaths(projectRoot, filePath)

View on GitHub (pinned to a0bd20f762)

Solutions

  1. Verify the handler value in your function config matches a real file path relative to the project root, e.g. "src/api/index.handler" for src/api/index.py.
  2. Check file-name casing and the .py extension; the resolver is case-sensitive and only accepts .py files.
  3. Confirm you are deploying from the directory you intend (root dir is resolved from cfgPath); move the code or fix the config path.
  4. Print/log the candidate search by checking the wrapped 'handler not found: ... (searched N candidate paths)' detail for hints.

Example fix

// before (sst.config.ts)
handler: "src/apoi.handler"

// after
handler: "src/api.handler"
Defensive patterns

Strategy: validation

Validate before calling

// node/bun, before deploy
import { existsSync } from "node:fs";
import path from "node:path";
const handler = "src/api.handler";
const file = handler.replace(/\.handler$/, ".py").split(".").slice(0, -1).join(".");
const dirs = ["", "src", "app", "functions", "lambda", "handlers", "lib"];
if (!dirs.some(d => existsSync(path.join(root, d, file + ".py"))))
  throw new Error(`handler target missing: ${file}.py`);

Try / catch

try { await deploy() } catch (e) {
  if (String(e).includes("failed to find Python file for handler"))
    console.error("Fix handler path in config:", String(e));
  throw e;
}

Prevention

When it happens

Trigger: Called from PythonRuntime.Build (and tests) with input.Handler set to a path whose derived file does not exist anywhere in the candidate directories (project root, src/, app/, functions/, lambda/, handlers/, lib/) relative to the resolved root dir of cfgPath.

Common situations: Typo in the handler field of the function config; handler written as a module symbol path that doesn't map to a file (e.g. wrong casing on case-sensitive filesystems); the sst.config.ts cfgPath root differs from where the Python code lives in a monorepo; the file was renamed but config not updated.

Related errors


AI-assisted analysis of anomalyco/sst@a0bd20f762 (2026-08-30). Data as JSON: /api/errors/7307fa44df201c7e. Report an issue: GitHub.