nektos/act · error

failed to read '%s' from action '%s' with path '%s' of step:

Error message

failed to read '%s' from action '%s' with path '%s' of step: %w

What it means

readActionImpl tries action.yml, then action.yaml, then Dockerfile when loading an action's metadata; each failed read is appended via addError. If no read succeeds, the accumulated errors are returned with this wrapper naming the step and actionPath. A single successful read clears the accumulated state, so this error means none of the metadata files could be read.

Source

Thrown at pkg/runner/action.go:48

}

type readAction func(ctx context.Context, step *model.Step, actionDir string, actionPath string, readFile actionYamlReader, writeFile fileWriter) (*model.Action, error)

type actionYamlReader func(filename string) (io.Reader, io.Closer, error)

type fileWriter func(filename string, data []byte, perm fs.FileMode) error

type runAction func(step actionStep, actionDir string, remoteAction *remoteAction) common.Executor

//go:embed res/trampoline.js
var trampoline embed.FS

func readActionImpl(ctx context.Context, step *model.Step, actionDir string, actionPath string, readFile actionYamlReader, writeFile fileWriter) (*model.Action, error) {
	logger := common.Logger(ctx)
	allErrors := []error{}
	addError := func(fileName string, err error) {
		if err != nil {
			allErrors = append(allErrors, fmt.Errorf("failed to read '%s' from action '%s' with path '%s' of step: %w", fileName, step.String(), actionPath, err))
		} else {
			// One successful read, clear error state
			allErrors = nil
		}
	}
	reader, closer, err := readFile("action.yml")
	addError("action.yml", err)
	if os.IsNotExist(err) {
		reader, closer, err = readFile("action.yaml")
		addError("action.yaml", err)
		if os.IsNotExist(err) {
			_, closer, err := readFile("Dockerfile")
			addError("Dockerfile", err)
			if err == nil {
				closer.Close()
				action := &model.Action{
					Name: "(Synthetic)",
					Runs: model.ActionRuns{

View on GitHub (pinned to 4f41128141)

Solutions

  1. Verify the action repository actually contains action.yml or action.yaml at the referenced path (add the subdirectory in `uses:` for monorepos).
  2. Clear the action cache (`rm -rf ~/.cache/act` or the configured cache dir) and re-run so the action re-clones.
  3. Check credentials/permissions for private actions — a failed clone leaves an empty dir that produces this error.
  4. Pin a known-good tag/SHA of the action in `uses:`.

Example fix

# before
- uses: myorg/monorepo@v1
# after (metadata lives in subdir)
- uses: myorg/monorepo/subdir/action@v1
Defensive patterns

Strategy: validation

Validate before calling

func actionMetadataExists(dir string) bool {
    for _, f := range []string{"action.yml", "action.yaml", "Dockerfile"} {
        if _, err := os.Stat(filepath.Join(dir, f)); err == nil { return true }
    }
    return false
}

Try / catch

if err != nil && strings.Contains(err.Error(), "failed to read 'action.yml'") {
    // check the action repo for metadata at the referenced path; clear the act cache and retry
}

Prevention

When it happens

Trigger: A remote action repository has no action.yml/action.yaml/Dockerfile at its root; a composite action's nested actionPath points at a subdirectory lacking metadata; the cloned action cache is incomplete after an interrupted fetch.

Common situations: Using an action whose repo renamed/moved metadata files; wrong `uses:` path for monorepo actions needing a subpath (e.g. missing `/subdir`); corrupted ~/.cache/act action downloads; private action fetched with bad credentials yielding empty dirs.

Related errors


AI-assisted analysis of nektos/act@4f41128141 (2026-08-15). Data as JSON: /api/errors/a3000737eb339c3a. Report an issue: GitHub.