hashicorp/terraform · error

couldn't read information for cloud run %s: %w

Error message

couldn't read information for cloud run %s: %w

What it means

Returned by ShowPlanForRun when Runs.ReadWithOptions fails with any error other than tfe.ErrResourceNotFound. The underlying error is wrapped so the caller sees the full cause (network, 5xx, context cancellation, JSON decode, etc.).

Source

Thrown at internal/cloud/backend_show.go:36

// returns it in a cloudplan.RemotePlanJSON wrapper struct (along with various
// metadata required by terraform show). It's intended for use by the terraform
// show command, in order to format and display a saved cloud plan.
func (b *Cloud) ShowPlanForRun(ctx context.Context, runID, runHostname string, redacted bool) (*cloudplan.RemotePlanJSON, error) {
	var jsonBytes []byte
	mode := plans.NormalMode
	var opts []plans.Quality

	// Bail early if wrong hostname
	if runHostname != b.Hostname {
		return nil, fmt.Errorf("hostname for run (%s) does not match the configured cloud integration (%s)", runHostname, b.Hostname)
	}

	// Get run and plan
	r, err := b.client.Runs.ReadWithOptions(ctx, runID, &tfe.RunReadOptions{Include: []tfe.RunIncludeOpt{tfe.RunPlan, tfe.RunWorkspace}})
	if err == tfe.ErrResourceNotFound {
		return nil, fmt.Errorf("couldn't read information for cloud run %s; make sure you've run `terraform login` and that you have permission to view the run", runID)
	} else if err != nil {
		return nil, fmt.Errorf("couldn't read information for cloud run %s: %w", runID, err)
	}

	// Sort out the run mode
	if r.IsDestroy {
		mode = plans.DestroyMode
	} else if r.RefreshOnly {
		mode = plans.RefreshOnlyMode
	}

	// Check that the plan actually finished
	switch r.Plan.Status {
	case tfe.PlanErrored:
		// Errored plans might still be displayable, but we want to mention it to the renderer.
		opts = append(opts, plans.Errored)
	case tfe.PlanFinished:
		// Good to go, but alert the renderer if it has no changes.
		if !r.Plan.HasChanges {
			opts = append(opts, plans.NoChanges)

View on GitHub (pinned to c9def3e214)

Solutions

  1. Read the wrapped %w cause to identify whether it is network, auth, or server-side.
  2. Retry after a brief wait; for 429/5xx back off exponentially.
  3. Check TFE/HCP status page and network/proxy connectivity from the runner.
  4. Increase the operation/context timeout if it is a deadline-exceeded error.

Example fix

// before
run, err := b.client.Runs.ReadWithOptions(ctx, runID, opts)
// after: inspect the wrapped error and retry on transient failures
if err != nil && !errors.Is(err, tfe.ErrResourceNotFound) {
    if isTransient(err) { /* backoff and retry */ } else { return fmt.Errorf("...: %w", err) }
}
Defensive patterns

Strategy: retry

Type guard

func isTransientReadErr(err error) bool {
    var netErr net.Error
    if errors.As(err, &netErr) && netErr.Timeout() { return true }
    if strings.Contains(err.Error(), "500") || strings.Contains(err.Error(), "502") || strings.Contains(err.Error(), "503") { return true }
    return false
}

Try / catch

var run *tfe.Run
backoff := time.Second
for attempt := 0; attempt < 3; attempt++ {
    run, err = b.client.Runs.ReadWithOptions(ctx, runID, opts)
    if err == nil { break }
    if errors.Is(err, tfe.ErrResourceNotFound) || !isTransientReadErr(err) { break }
    time.Sleep(backoff); backoff *= 2
}

Prevention

When it happens

Trigger: API call to read the run returns a non-404 failure: 5xx server error, timeout, TLS/DNS error, rate limiting, context cancellation, or an unexpected response body.

Common situations: TFE/HCP outage or degraded API; transient network blip; proxy/firewall blocking the API; CI runner with short context timeouts; rate-limited token.

Related errors


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