{"record":{"id":"e9328ea1995333bb","repo":"hashicorp/terraform","slug":"failed-to-send-completed-event-w","errorCode":null,"errorMessage":"failed to send completed event: %w","messagePattern":"failed to send completed event: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/grpcwrap/provider.go","lineNumber":933,"sourceCode":"\t\t\tserver.Send(&tfplugin5.InvokeAction_Event{\n\t\t\t\tType: &tfplugin5.InvokeAction_Event_Progress_{\n\t\t\t\t\tProgress: &tfplugin5.InvokeAction_Event_Progress{\n\t\t\t\t\t\tMessage: invokeEvt.Message,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t})\n\n\t\tcase providers.InvokeActionEvent_Completed:\n\t\t\tcompleted := &tfplugin5.InvokeAction_Event_Completed{}\n\t\t\tcompleted.Diagnostics = convert.AppendProtoDiag(completed.Diagnostics, invokeEvt.Diagnostics)\n\n\t\t\terr := server.Send(&tfplugin5.InvokeAction_Event{\n\t\t\t\tType: &tfplugin5.InvokeAction_Event_Completed_{\n\t\t\t\t\tCompleted: completed,\n\t\t\t\t},\n\t\t\t})\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"failed to send completed event: %w\", err)\n\t\t\t}\n\t\t}\n\n\t}\n\n\treturn nil\n}\n\nfunc (p *provider) ValidateActionConfig(_ context.Context, req *tfplugin5.ValidateActionConfig_Request) (*tfplugin5.ValidateActionConfig_Response, error) {\n\tresp := &tfplugin5.ValidateActionConfig_Response{}\n\tty := p.schema.Actions[req.TypeName].ConfigSchema.ImpliedType()\n\n\tconfigVal, err := decodeDynamicValue(req.Config, ty)\n\tif err != nil {\n\t\tresp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)\n\t\treturn resp, nil\n\t}\n","sourceCodeStart":915,"sourceCodeEnd":951,"githubUrl":"https://github.com/hashicorp/terraform/blob/d32a084675427f5ac3f7d2868578ef8b2c1dc525/internal/grpcwrap/provider.go#L915-L951","documentation":"Returned by the InvokeAction streaming handler when server.Send of the Completed event fails. The action itself already ran; only the final gRPC stream write back to Terraform core failed. The %w carries the underlying transport error (typically a status code such as Canceled or Unavailable).","triggerScenarios":"server.Send of the InvokeAction_Event_Completed_ message returns a non-nil error because the client disconnected, the context was cancelled, or the transport broke during the final write.","commonSituations":"User interrupted the action (Ctrl-C); context deadline exceeded on a long-running action; gRPC connection dropped; terraform core exited mid-action.","solutions":["Check whether the operation was cancelled intentionally (interrupt or timeout) before treating as a failure.","Inspect the wrapped error's status code via status.Code(err) to distinguish Canceled/Unavailable from real failures.","Increase operation timeouts for long-running actions.","Re-run the action, but first verify remote side effects: a Completed-delivery failure does not guarantee the action's side effects were not applied.","Verify network stability between terraform core and the provider process."],"exampleFix":"// before\nif err := server.Send(completedEvt); err != nil {\n    return fmt.Errorf(\"failed to send completed event: %w\", err)\n}\n// after: keep the error but make it actionable to callers\nif err := server.Send(completedEvt); err != nil {\n    return status.Errorf(codes.Unavailable, \"failed to send completed event (action may still have applied): %v\", err)\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"// Completed-event delivery failure is a transport/cancellation issue.\nerr := runInvoke(client, actionType, config)\nif err != nil {\n    st, ok := status.FromError(err)\n    if ok && (st.Code() == codes.Canceled || st.Code() == codes.DeadlineExceeded) {\n        // client cancelled; verify remote side effects, do not blindly retry\n    } else if ok && st.Code() == codes.Unavailable {\n        // transport dropped; safe to retry after reconnect\n    }\n}","preventionTips":["For long-running actions, set a context deadline generous enough to outlast the action plus the final send.","Before retrying, verify the action's side effects did not already apply.","Surface status codes so cancellation is distinguishable from real failure."],"tags":["terraform","grpc","streaming","action","network","cancellation"],"backgroundTag":null,"analyzedSha":"d32a084675427f5ac3f7d2868578ef8b2c1dc525","analyzedAt":"2026-08-11T18:43:52.779Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}