nektos/act · error
invalid step status %q
Error message
invalid step status %q
What it means
stepStatus.UnmarshalText accepts only the strings "success", "failure", and "skipped" (the only values in stepStatusStrings). Any other string while decoding a StepResult's Conclusion/Outcome from JSON — e.g. "cancelled" — produces this error. Note that "cancelled" is a valid GitHub conclusion but is NOT in this enum.
Source
Thrown at pkg/model/step_result.go:31
var stepStatusStrings = [...]string{
"success",
"failure",
"skipped",
}
func (s stepStatus) MarshalText() ([]byte, error) {
return []byte(s.String()), nil
}
func (s *stepStatus) UnmarshalText(b []byte) error {
str := string(b)
for i, name := range stepStatusStrings {
if name == str {
*s = stepStatus(i)
return nil
}
}
return fmt.Errorf("invalid step status %q", str)
}
func (s stepStatus) String() string {
if int(s) >= len(stepStatusStrings) {
return ""
}
return stepStatusStrings[s]
}
type StepResult struct {
Outputs map[string]string `json:"outputs"`
Conclusion stepStatus `json:"conclusion"`
Outcome stepStatus `json:"outcome"`
}
View on GitHub (pinned to 4f41128141)
Solutions
- Map external conclusions onto the three supported values before decoding: cancelled→skipped, neutral→success (or skip the record).
- Fix the JSON source to emit only success|failure|skipped exactly lowercase.
- If you need cancelled semantics, model it at a higher level rather than in model.StepResult.
Example fix
// before
var r model.StepResult
json.Unmarshal(data, &r) // data has "cancelled"
// after
allowed := map[string]bool{"success": true, "failure": true, "skipped": true}
if !allowed[raw] {
raw = "skipped"
} Defensive patterns
Strategy: validation
Validate before calling
var valid = map[string]bool{"success": true, "failure": true, "skipped": true}
if s, ok := raw["conclusion"].(string); ok && !valid[s] {
raw["conclusion"] = "skipped" // normalize external conclusions like "cancelled"
} Type guard
func isKnownStepStatus(s string) bool {
switch s {
case "success", "failure", "skipped":
return true
}
return false
} Try / catch
var r model.StepResult
if err := json.Unmarshal(data, &r); err != nil {
if strings.Contains(err.Error(), "invalid step status") {
// normalize the conclusion field and retry once
}
} Prevention
- Only persist the three canonical lowercase values when serializing step results.
- Translate GitHub API conclusions (cancelled, neutral, timed_out) at your integration boundary.
- Pin act versions when round-tripping result JSON between systems.
When it happens
Trigger: Decoding persisted or externally produced step-result JSON whose conclusion is "cancelled", "neutral", or any casing/typo variant; round-tripping results between act versions or from the GitHub API into model.StepResult.
Common situations: Consuming act as a library and unmarshalling GitHub Actions API step data; fixtures copied from GitHub UI that use "cancelled"; JSON with "Success" (capitalized).
Related errors
AI-assisted analysis of nektos/act@4f41128141 (2026-08-15).
Data as JSON: /api/errors/3d3923316820662e.
Report an issue: GitHub.