hashicorp/terraform · error

%s soft failed. %s

Error message

%s soft failed.
%s

What it means

In checkPolicy(), when pc.Status == tfe.PolicySoftFailed AND the run cannot be overridden in the current context: it's a plan operation, or there is no interactive UI (UIIn/UIOut nil), or the policy check is not overridable (pc.Actions.IsOverridable false) or the token lacks override permission (pc.Permissions.CanOverride false). A soft failure is overridable in principle, but not from this code path, so it surfaces as an error with a run URL.

Source

Thrown at internal/backend/remote/backend_common.go:451

			}
		}

		switch pc.Status {
		case tfe.PolicyPasses:
			if (r.HasChanges && op.Type == backendrun.OperationTypeApply || i < len(r.PolicyChecks)-1) && b.CLI != nil {
				b.CLI.Output("\n------------------------------------------------------------------------")
			}
			continue
		case tfe.PolicyErrored:
			return fmt.Errorf("%s errored.", msgPrefix)
		case tfe.PolicyHardFailed:
			return fmt.Errorf("%s hard failed.", msgPrefix)
		case tfe.PolicySoftFailed:
			runURL := fmt.Sprintf(runHeaderErr, b.hostname, b.organization, op.Workspace, r.ID)

			if op.Type == backendrun.OperationTypePlan || op.UIOut == nil || op.UIIn == nil ||
				!pc.Actions.IsOverridable || !pc.Permissions.CanOverride {
				return fmt.Errorf("%s soft failed.\n%s", msgPrefix, runURL)
			}

			if op.AutoApprove {
				if _, err = b.client.PolicyChecks.Override(stopCtx, pc.ID); err != nil {
					return generalError(fmt.Sprintf("Failed to override policy check.\n%s", runURL), err)
				}
			} else {
				opts := &terraform.InputOpts{
					Id:          "override",
					Query:       "\nDo you want to override the soft failed policy check?",
					Description: "Only 'override' will be accepted to override.",
				}
				err = b.confirm(stopCtx, op, opts, r, "override")
				if err != nil && err != errRunOverridden {
					return fmt.Errorf("Failed to override: %w\n%s\n", err, runURL)
				}

				if err != errRunOverridden {

View on GitHub (pinned to c9def3e214)

Solutions

  1. Follow the run URL in the message to override (or discard) the soft failure in the HCP/TFE UI.
  2. Fix the configuration to satisfy the policy so no override is needed.
  3. Grant the token's team the 'Override Soft Policy' permission AND run apply (not plan) interactively so the override prompt appears next time.
  4. Use `terraform apply -auto-approve` which takes the auto-override branch (line 454) if permissions allow.
Defensive patterns

Strategy: try-catch

Validate before calling

// Only attempt override path when permissions + apply context allow it.
func canOverrideHere(op *backendrun.Operation, pc *tfe.PolicyCheck) bool {
    return op.Type != backendrun.OperationTypePlan &&
        op.UIIn != nil && op.UIOut != nil &&
        pc.Actions.IsOverridable && pc.Permissions.CanOverride
}

Type guard

func isSoftFailed(s tfe.PolicyStatus) bool {
    return s == tfe.PolicySoftFailed
}

Try / catch

if err := b.checkPolicy(stopCtx, cancelCtx, op, r); err != nil {
    if strings.Contains(err.Error(), "soft failed") {
        // direct user to the run URL in the message to override via UI
    }
    return err
}

Prevention

When it happens

Trigger: A soft-mandatory policy fails during: a `plan` (op.Type == OperationTypePlan, no override offered for plans), a non-interactive run (no terminal/UIIn), or when the policy/token disallows override. The user is given the run URL to act in the UI.

Common situations: Running `terraform plan` remotely where a soft policy fails (plans never prompt to override); running in CI with no interactive UI so the override prompt can't appear; the token's team lacks 'Override soft policy' permission.

Related errors


AI-assisted analysis of hashicorp/terraform@c9def3e214 (2026-08-07). Data as JSON: /api/errors/7397cc94ccdb7ff3. Report an issue: GitHub.