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

  1. Map external conclusions onto the three supported values before decoding: cancelled→skipped, neutral→success (or skip the record).
  2. Fix the JSON source to emit only success|failure|skipped exactly lowercase.
  3. 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

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.