From 29058e6501b1db3a17072edcf92ecdab0ab010ee Mon Sep 17 00:00:00 2001 From: Derek McGowan Date: Thu, 6 Aug 2026 17:19:05 -0700 Subject: [PATCH] Add more context to the shim delete error When a shim delete hits a timeout, currently the error message does not indicate that the delete was killed rather than failed to complete. Signed-off-by: Derek McGowan --- core/runtime/v2/binary.go | 31 ++++++++++++++++++++++++++----- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/core/runtime/v2/binary.go b/core/runtime/v2/binary.go index 253b7deaed..4878e3644e 100644 --- a/core/runtime/v2/binary.go +++ b/core/runtime/v2/binary.go @@ -116,7 +116,7 @@ func (b *binary) Start(ctx context.Context, opts *types.Any, onClose func()) (_ }() out, err := cmd.CombinedOutput() if err != nil { - return nil, fmt.Errorf("%s: %w", out, err) + return nil, shimCallError(ctx.Err(), out, err) } onCloseWithShimLog := func() { onClose() @@ -191,11 +191,12 @@ func (b *binary) Delete(ctx context.Context) (*runtime.Exit, error) { cmd.Stderr = errb if err := cmd.Run(); err != nil { log.G(ctx).WithFields(log.Fields{ - "cmd": cmd.String(), - "error": err, - "id": b.bundle.ID, + "cmd": cmd.String(), + "error": err, + "id": b.bundle.ID, + "stderr": errb.String(), }).Error("failed to delete dead shim") - return nil, fmt.Errorf("%s: %w", errb.String(), err) + return nil, shimCallError(ctx.Err(), errb.Bytes(), err) } if s := errb.String(); s != "" { log.G(ctx).WithFields(log.Fields{ @@ -216,3 +217,23 @@ func (b *binary) Delete(ctx context.Context) (*runtime.Exit, error) { Pid: response.Pid, }, nil } + +// shimCallError builds an error for a failed shim binary invocation. +// +// client.Command is run via exec.CommandContext, which kills the process +// once ctx is done. On Windows that kill is TerminateProcess(handle, 1), +// which is indistinguishable from the shim genuinely calling os.Exit(1), +// and os/exec reports the wait status in preference to the context error. +// A killed shim also writes nothing to stderr, so without surfacing ctxErr +// the resulting message degenerates to ": exit status 1" with no +// indication that containerd killed the process rather than the shim +// exiting on its own. +func shimCallError(ctxErr error, stderr []byte, err error) error { + if ctxErr != nil { + err = fmt.Errorf("shim killed after %w: %w", ctxErr, err) + } + if s := bytes.TrimSpace(stderr); len(s) > 0 { + err = fmt.Errorf("%s: %w", s, err) + } + return err +}