opentofu/opentofu · error

couldn't read unredacted JSON plan data for cloud run %s; ma

Error message

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

What it means

Cloud.ShowPlanForRun got 404 when fetching the unredacted plan JSON via client.Plans.ReadJSONOutput. Unredacted plan output contains secret values (sensitive attribute values in full), so TFC/TFE only serves it to workspace-level admin tokens; a 404 here means no access or gone, and the message calls out the admin requirement.

Source

Thrown at internal/cloud/backend_show.go:74

			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 `tofu 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 `tofu 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 3561785c48)

Solutions

  1. Use a token whose identity has admin permission on that workspace (organization owners, or a team granted workspace admin), then retry
  2. If you do not need secret values, show the redacted variant instead (default `tofu show` behavior redacts sensitive values)
  3. Verify you are logged in to the correct hostname/org via `tofu login`
  4. If permissions are right but the plan is old, the run may have been purged — create a new plan

Example fix

# before: team token without workspace admin
$ tofu show -json plan.tfplan
# Error: couldn't read unredacted JSON plan data for cloud run run-XXXX...

# after: use an org-owner token for this host
$ export TF_TOKEN_app_terraform_io=<admin-token>
$ tofu show -json plan.tfplan
Defensive patterns

Strategy: validation

Validate before calling

// Unredacted output needs workspace admin: check the identity first.
perms, _ := client.Workspaces.ReadPermissions(ctx, wsID) // conceptual permission read
if !workspaceAdmin(perms) {
    fmt.Fprintln(os.Stderr, "falling back to redacted plan output")
    redacted = true
}

Type guard

func canReadUnredacted(wsPerms *tfe.WorkspacePermissions) bool {
	return wsPerms != nil && wsPerms.Admin // conceptual: gate on workspace admin
}

Try / catch

b, err := client.Plans.ReadJSONOutput(ctx, planID)
if errors.Is(err, tfe.ErrResourceNotFound) && !redacted {
    // retry once with redacted output rather than failing the pipeline
    b, err = readRedactedPlan(ctx, baseURL, token, planID)
}

Prevention

When it happens

Trigger: Showing a saved cloud plan through the unredacted path (e.g., `tofu show -json` where the caller requested unredacted output) with a token that is not a workspace admin, or credentials missing/expired, or the plan no longer existing.

Common situations: CI token with broad run permissions but not workspace admin; team-level tokens reading plans for audit; user whose admin role was revoked after the plan was saved.

Related errors


AI-assisted analysis of opentofu/opentofu@3561785c48 (2026-08-15). Data as JSON: /api/errors/15a8de35ebbf8433. Report an issue: GitHub.