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
- Check the wrapped error (errors.Unwrap / errors.Is) to distinguish context.Canceled from real transport failures.
- Ensure the client/connection stays alive for the duration of the action; raise gRPC keepalive timeouts if the action runs long.
- If the plugin process crashed, restart terraform and re-run the action; verify provider process limits (memory, OOM).
- 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
- Keep the gRPC client alive for the full duration of long-running actions.
- Set gRPC keepalive timeouts generously relative to action duration.
- In tests, fully drain the event stream instead of cancelling the context early.
- Inspect the wrapped error before treating a send failure as fatal.
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
- failed to send completed event: %w
- wrapped err: %w
- error writing state: %w
- expected to receive state in %d bytes, actually received %d
- action schema not found for action %q
AI-assisted analysis of hashicorp/terraform@d32a084675 (2026-08-11).
Data as JSON: /api/errors/920d9d9c770a8e52.
Report an issue: GitHub.