nektos/act · error
unable to read workflow '%s': file is empty: %w
Error message
unable to read workflow '%s': file is empty: %w
What it means
Returned by NewWorkflowPlanner when ReadWorkflow on a .yml/.yaml file in .github/workflows returns io.EOF, meaning the file is completely empty. The planner scans every YAML file in the directory, so a single empty file aborts planning.
Source
Thrown at pkg/model/planner.go:131
workflowDirEntry: fs.FileInfoToDirEntry(fi),
})
}
wp := new(workflowPlanner)
for _, wf := range workflows {
ext := filepath.Ext(wf.workflowDirEntry.Name())
if ext == ".yml" || ext == ".yaml" {
f, err := os.Open(filepath.Join(wf.dirPath, wf.workflowDirEntry.Name()))
if err != nil {
return nil, err
}
log.Debugf("Reading workflow '%s'", f.Name())
workflow, err := ReadWorkflow(f, strict)
if err != nil {
_ = f.Close()
if err == io.EOF {
return nil, fmt.Errorf("unable to read workflow '%s': file is empty: %w", wf.workflowDirEntry.Name(), err)
}
return nil, fmt.Errorf("workflow is not valid. '%s': %w", wf.workflowDirEntry.Name(), err)
}
_, err = f.Seek(0, 0)
if err != nil {
_ = f.Close()
return nil, fmt.Errorf("error occurring when resetting io pointer in '%s': %w", wf.workflowDirEntry.Name(), err)
}
workflow.File = wf.workflowDirEntry.Name()
if workflow.Name == "" {
workflow.Name = wf.workflowDirEntry.Name()
}
err = validateJobName(workflow)
if err != nil {
_ = f.Close()
return nil, errView on GitHub (pinned to 4f41128141)
Solutions
- Delete or populate the empty .yml/.yaml file in .github/workflows.
- Run `find .github/workflows -name '*.yml' -empty` to locate the offending file.
- Add minimal valid content (name, on, jobs) if the file is intentionally kept.
Example fix
# delete the empty file
rm .github/workflows/empty.yml
# or give it minimal content
name: placeholder
on: push
jobs:
build:
runs-on: ubuntu-latest
steps:
- run: echo ok Defensive patterns
Strategy: validation
Validate before calling
// guard: reject empty workflow files before planning
entries, _ := os.ReadDir(".github/workflows")
for _, e := range entries {
if strings.HasSuffix(e.Name(), ".yml") || strings.HasSuffix(e.Name(), ".yaml") {
if fi, _ := e.Info(); fi.Size() == 0 {
return fmt.Errorf("%s is empty", e.Name())
}
}
} Try / catch
if err != nil && strings.Contains(err.Error(), "file is empty") {
// locate and delete/fill the named file, then re-run
} Prevention
- Add a CI check that .github/workflows contains no zero-byte YAML files.
- Never leave touch-created placeholder workflows in the tree.
- Use yamllint in CI; it also flags empty files.
When it happens
Trigger: An empty .github/workflows/*.yml file exists (created by touch, a failed editor save, or a template placeholder). os.Open succeeds, ReadWorkflow hits EOF on the first read, and the planner wraps it with this message.
Common situations: Leftover placeholder files like `.github/workflows/tmp.yml`; CI scaffolding that creates files before filling them; a commit that accidentally emptied a workflow file.
Related errors
- workflow is not valid. '%s': %w
- error occurring when resetting io pointer in '%s': %w
- unable to build dependency graph for %s (%s)
- Actions YAML Schema Validation Error detected:\nFor more inf
- invalid Step %v: missing run or uses key
AI-assisted analysis of nektos/act@4f41128141 (2026-08-15).
Data as JSON: /api/errors/307c2d3acac73259.
Report an issue: GitHub.