hashicorp/terraform · error

wrapped err

Error message

wrapped err: %w

What it means

Returned (after the receive loop) by the tfplugin6 WriteStateBytes handler when srv.Recv() returned an error other than io.EOF. The error is captured into grpcErr, the loop breaks, and grpcErr is returned once the loop exits. The %w carries the underlying gRPC stream error.

Solutions

  1. Inspect status.Code(err) on the wrapped value: Canceled/DeadlineExceeded imply interruption, ResourceExhausted implies message size, Unavailable implies transport.
  2. Retry the state write once the underlying condition clears.
  3. Ensure each chunk stays within the configured gRPC max message size.
  4. Confirm the client remains connected for the entire streaming write.
  5. Check provider/core logs for the upstream cancellation cause.

Example fix

// before
chunk, err := srv.Recv()
if err != nil && err != io.EOF {
    grpcErr = fmt.Errorf("wrapped err: %w", err)
}
// after: surface the status code for diagnosability
if err != nil && err != io.EOF {
    grpcErr = status.Errorf(status.Code(err), "receiving state chunk: %v", err)
}
Defensive patterns

Strategy: try-catch

Try / catch

// Handle a mid-stream receive failure on WriteStateBytes.
err := client.WriteStateBytes(ctx, chunks)
if err != nil {
    st, ok := status.FromError(err)
    switch {
    case !ok:
        return err // non-gRPC error
    case st.Code() == codes.Canceled || st.Code() == codes.DeadlineExceeded:
        return fmt.Errorf("state write interrupted: %v", err) // do not blindly retry
    case st.Code() == codes.ResourceExhausted:
        return fmt.Errorf("state chunk exceeded max message size: %v", err)
    case st.Code() == codes.Unavailable:
        return retryableErr(err) // safe to retry after reconnect
    }
}

Prevention

When it happens

Trigger: srv.Recv() inside the WriteStateBytes streaming loop returns a non-nil, non-io.EOF error: client disconnect, context cancellation, transport failure, or message-size-limit exceeded.

Common situations: State upload interrupted by the user; network drop between core and provider; context deadline; oversized chunk beyond gRPC max receive message size.

Related errors


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

Appendix: source

Thrown at internal/grpcwrap/provider6.go:1075

		rangeStart += byteCount
	}
}

func (p *provider6) WriteStateBytes(srv tfplugin6.Provider_WriteStateBytesServer) error {
	var typeName string
	var stateId string

	state := bytes.Buffer{}
	var grpcErr error
	var totalReceivedBytes int
	var expectedTotalLength int64
	for {
		chunk, err := srv.Recv()
		if err == io.EOF {
			break
		}
		if err != nil {
			grpcErr = fmt.Errorf("wrapped err: %w", err)
			break
		}
		if expectedTotalLength == 0 {
			// On the first iteration
			expectedTotalLength = chunk.TotalLength // record expected length
			if chunk.Meta != nil {
				// We expect the Meta to be set on the first message, only
				typeName = chunk.Meta.TypeName
				stateId = chunk.Meta.StateId
			} else {
				panic("expected Meta to be set on first chunk sent to WriteStateBytes")
			}
		}

		n, err := state.Write(chunk.Bytes)
		if err != nil {
			return fmt.Errorf("error writing state: %w", err)
		}

View on GitHub (pinned to d32a084675)