hashicorp/terraform · error

couldn't read unredacted JSON plan data for cloud run

Error message

couldn't read unredacted JSON plan data for cloud run %s; make sure you've run `terraform login` and that you have admin permissions on the workspace

What it means

Thrown by Cloud.ShowPlanForRun when b.client.Plans.ReadJSONOutput returns tfe.ErrResourceNotFound while requesting the UNREDACTED plan JSON. Unredacted plan output contains sensitive values and requires admin permissions on the workspace; a 404 here specifically signals insufficient privilege or missing auth.

Solutions

  1. Have a workspace admin perform the unredacted show, or grant admin permission to your team.
  2. Use the redacted plan output instead (default path) if you only need the structural diff.
  3. Run `terraform login` to ensure a valid token is used.
Defensive patterns

Strategy: validation

Validate before calling

// Only request unredacted output when admin permission is confirmed.
if !callerIsAdmin { /* use redacted path */ }

Try / catch

jsonBytes, err = b.client.Plans.ReadJSONOutput(ctx, planID)
if err == tfe.ErrResourceNotFound {
    // not admin or not authenticated; fall back to redacted or surface
}

Prevention

When it happens

Trigger: redacted=false path; ReadJSONOutput returns 404. The caller requested the full unredacted plan but the token's team lacks admin permissions on the workspace, so TFE hides the resource (404 instead of 403).

Common situations: Using `terraform show` with a flag requesting unredacted output as a non-admin; token from a read-only team; workspace admin role not granted to the caller's team.

Related errors


AI-assisted analysis of hashicorp/terraform@d32a084675 (2026-08-11). Data as JSON: /api/errors/a78932f384d8629c. Report an issue: GitHub.

Appendix: source

Thrown at internal/cloud/backend_show.go:72

			opts = append(opts, plans.NoChanges)
		}
	default:
		// Bail, we can't use this.
		err = fmt.Errorf("can't display a cloud plan that is currently %s", r.Plan.Status)
		return nil, err
	}

	// Fetch the json plan!
	if redacted {
		jsonBytes, err = readRedactedPlan(ctx, b.client.BaseURL(), b.Token, r.Plan.ID)
	} else {
		jsonBytes, err = b.client.Plans.ReadJSONOutput(ctx, r.Plan.ID)
	}
	if err == tfe.ErrResourceNotFound {
		if redacted {
			return nil, fmt.Errorf("couldn't read plan data for cloud run %s; make sure you've run `terraform login` and that you have permission to view the run", runID)
		} else {
			return nil, fmt.Errorf("couldn't read unredacted JSON plan data for cloud run %s; make sure you've run `terraform login` and that you have admin permissions on the workspace", runID)
		}
	} else if err != nil {
		return nil, fmt.Errorf("couldn't read plan data for cloud run %s: %w", runID, err)
	}

	// Format a run header and footer
	header := strings.TrimSpace(fmt.Sprintf(runHeader, b.Hostname, b.Organization, r.Workspace.Name, r.ID))
	footer := strings.TrimSpace(statusFooter(r.Status, r.Actions.IsConfirmable, r.Workspace.Locked))

	out := &cloudplan.RemotePlanJSON{
		JSONBytes: jsonBytes,
		Redacted:  redacted,
		Mode:      mode,
		Qualities: opts,
		RunHeader: header,
		RunFooter: footer,
	}

View on GitHub (pinned to d32a084675)