hashicorp/terraform · error

failed to send completed event: %w

Error message

failed to send completed event: %w

What it means

Returned when the gRPC server.Send of the Completed event on the InvokeAction stream fails. It wraps the underlying transport error with %w so the caller can inspect cause. The action itself finished; only the final completion notification to the client failed to transmit.

Source

Thrown at internal/grpcwrap/provider6.go:1261

			server.Send(&tfplugin6.InvokeAction_Event{
				Type: &tfplugin6.InvokeAction_Event_Progress_{
					Progress: &tfplugin6.InvokeAction_Event_Progress{
						Message: invokeEvt.Message,
					},
				},
			})

		case providers.InvokeActionEvent_Completed:
			completed := &tfplugin6.InvokeAction_Event_Completed{}
			completed.Diagnostics = convert.AppendProtoDiag(completed.Diagnostics, invokeEvt.Diagnostics)

			err := server.Send(&tfplugin6.InvokeAction_Event{
				Type: &tfplugin6.InvokeAction_Event_Completed_{
					Completed: completed,
				},
			})
			if err != nil {
				return fmt.Errorf("failed to send completed event: %w", err)
			}
		}

	}

	return nil
}

func (p *provider6) ValidateActionConfig(_ context.Context, req *tfplugin6.ValidateActionConfig_Request) (*tfplugin6.ValidateActionConfig_Response, error) {
	resp := &tfplugin6.ValidateActionConfig_Response{}
	ty := p.schema.Actions[req.TypeName].ConfigSchema.ImpliedType()

	configVal, err := decodeDynamicValue6(req.Config, ty)
	if err != nil {
		resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
		return resp, nil
	}

View on GitHub (pinned to d32a084675)

Solutions

  1. Check the wrapped error (errors.Unwrap / errors.Is) to distinguish context.Canceled from real transport failures.
  2. Ensure the client/connection stays alive for the duration of the action; raise gRPC keepalive timeouts if the action runs long.
  3. If the plugin process crashed, restart terraform and re-run the action; verify provider process limits (memory, OOM).
  4. In tests, drain the event stream to completion rather than cancelling the context early.

Example fix

// before
if err := server.Send(completedEvt); err != nil {
    return fmt.Errorf("failed to send completed event: %w", err)
}

// caller-side handling
if errors.Is(err, context.Canceled) { /* client cancelled: safe to ignore */ }
Defensive patterns

Strategy: try-catch

Try / catch

if err := server.Send(completedEvt); err != nil {
    if errors.Is(err, context.Canceled) || errors.Is(err, context.DeadlineExceeded) {
        // client went away; nothing useful to do
        return nil
    }
    return fmt.Errorf("failed to send completed event: %w", err)
}

Prevention

When it happens

Trigger: The InvokeAction Impl loops over provider action events; on InvokeActionEvent_Completed it calls server.Send(...) for an InvokeAction_Event_Completed_ message. If the gRPC stream is broken (client gone, context cancelled, network drop), Send returns a non-nil error and this wraps it.

Common situations: Client disconnect or SIGINT during a long-running action, gRPC keepalive timeout, plugin process killed mid-stream, or context deadline exceeded while the action was emitting its completion event.

Related errors


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