nektos/act · error
workflow is not valid. '%s': Job name '%s' is invalid. Names
Error message
workflow is not valid. '%s': Job name '%s' is invalid. Names must start with a letter or '_' and contain only alphanumeric characters, '-', or '_'
What it means
validateJobName rejects a job ID that does not match ^([[:alpha:]_][[:alnum:]_-]*)$ — it must start with a letter or underscore and contain only letters, digits, underscores, and hyphens. This mirrors GitHub's job-ID rules because job IDs become `needs` references and step outputs are keyed off them.
Source
Thrown at pkg/model/planner.go:190
if workflow.Name == "" {
workflow.Name = name
}
err = validateJobName(workflow)
if err != nil {
return nil, err
}
wp.workflows = append(wp.workflows, workflow)
return wp, nil
}
func validateJobName(workflow *Workflow) error {
jobNameRegex := regexp.MustCompile(`^([[:alpha:]_][[:alnum:]_\-]*)$`)
for k := range workflow.Jobs {
if ok := jobNameRegex.MatchString(k); !ok {
return fmt.Errorf("workflow is not valid. '%s': Job name '%s' is invalid. Names must start with a letter or '_' and contain only alphanumeric characters, '-', or '_'", workflow.Name, k)
}
}
return nil
}
type workflowPlanner struct {
workflows []*Workflow
}
// PlanEvent builds a new list of runs to execute in parallel for an event name
func (wp *workflowPlanner) PlanEvent(eventName string) (*Plan, error) {
plan := new(Plan)
if len(wp.workflows) == 0 {
log.Debug("no workflows found by planner")
return plan, nil
}
var lastErr error
View on GitHub (pinned to 4f41128141)
Solutions
- Rename the job key to start with a letter or underscore and use only [A-Za-z0-9_-].
- Move the human-readable label to `name:` under the job.
- Update every `needs:` reference and `jobs.<id>.outputs` consumer to the new ID.
Example fix
# before
jobs:
1-deploy:
name: Deploy prod
# after
jobs:
deploy-prod:
name: 1-deploy (Deploy prod) Defensive patterns
Strategy: validation
Validate before calling
var jobIDRe = regexp.MustCompile(`^[[:alpha:]_][[:alnum:]_-]*$`)
for id := range wf.Jobs {
if !jobIDRe.MatchString(id) {
return fmt.Errorf("invalid job id %q", id)
}
} Type guard
func isValidJobID(id string) bool {
if id == "" { return false }
for i, r := range id {
switch {
case r >= 'a' && r <= 'z', r >= 'A' && r <= 'Z', r == '_':
case r >= '0' && r <= '9', r == '-':
if i == 0 { return false }
default:
return false
}
}
return true
} Prevention
- Use only [a-z0-9_-] job IDs starting with a letter or underscore.
- Put display strings in `name:`, never in the job key.
- Update all `needs:` references after renaming a job ID.
When it happens
Trigger: A jobs: key like `1-deploy` (starts with digit), `my.job` (dot), `build test` (space), or `build!` (punctuation). The map key under `jobs:` is checked, not the job's display `name:`.
Common situations: Auto-generated job IDs from scaffolding tools that include dots/spaces; renaming jobs to match ticket numbers; confusion between `name:` (any string allowed) and the job ID key.
Related errors
- workflow is not valid. '%s': %w
- Actions YAML Schema Validation Error detected:\nFor more inf
- Actions YAML Strict Schema Validation Error detected:\nFor m
- the workflow is not valid. Matrix exclude key %q does not ma
- `uses` key references invalid workflow path '%s'. Must start
AI-assisted analysis of nektos/act@4f41128141 (2026-08-15).
Data as JSON: /api/errors/b72ac1387c86aaf0.
Report an issue: GitHub.