From 5c09ea55e1d8bba61bb4e1d776b151c78d2fab02 Mon Sep 17 00:00:00 2001 From: maiconfontana Date: Tue, 7 Jul 2026 15:37:33 -0300 Subject: [PATCH] Fix: run exec-form commands as container Command, not Args OpenHands V1 (app_server, e.g. 1.8.0) sends the sandbox command in exec form, e.g. ["/usr/local/bin/openhands-agent-server", "--port", "60000"]. The agent-server image ENTRYPOINT is ["tini","--","/usr/local/bin/openhands-agent-server"], so passing the command through as container Args ran `tini -- openhands-agent-server /usr/local/bin/openhands-agent-server --port 60000` -- the binary received its own path as a positional argument and aborted with "unrecognized arguments", CrashLoopBackOff. When the command starts with an absolute path (exec form), set it as the container Command so it replaces the image ENTRYPOINT and runs verbatim. Non-absolute multi-arg commands still pass as Args to the ENTRYPOINT, and single-string commands still run via `bash -c`. Co-Authored-By: Claude Fable 5 --- pkg/k8s/client.go | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/pkg/k8s/client.go b/pkg/k8s/client.go index 5138267..ccb2c34 100644 --- a/pkg/k8s/client.go +++ b/pkg/k8s/client.go @@ -213,15 +213,34 @@ func (c *Client) createPod(ctx context.Context, req *types.StartRequest, runtime }) } - // Use image ENTRYPOINT (e.g. /openhands/entrypoint.sh for update-ca-certificates) - // and pass request command as Args so the entrypoint receives them as "$@". - // If we set Command we would replace the image ENTRYPOINT and the entrypoint would never run. + // How the request command is turned into a container Command/Args. + // + // OpenHands V1 sends the FULL command in exec form, e.g. + // ["/usr/local/bin/openhands-agent-server", "--port", "60000"] + // The agent-server image ENTRYPOINT is ["tini","--","/usr/local/bin/openhands-agent-server"]. + // Passing the full command as Args (the previous behavior) appends it to that ENTRYPOINT, so the + // container runs `tini -- openhands-agent-server /usr/local/bin/openhands-agent-server --port 60000` + // and the agent-server binary receives its own path as a positional arg -> it aborts with + // "unrecognized arguments: /usr/local/bin/openhands-agent-server" and CrashLoops. + // + // Fix: when the command starts with an absolute path (a real binary/exec form, which is what + // OpenHands sends), set it as the container Command so it REPLACES the image ENTRYPOINT and runs + // exactly as given. A single non-path string is still run via `bash -c` (shell form). This keeps + // exec-form commands working with images whose ENTRYPOINT is the target binary (agent-server), + // while preserving shell-string behavior. var command []string var args []string - if len(req.Command) > 1 { + switch { + case len(req.Command) > 1 && strings.HasPrefix(req.Command[0], "/"): + // Exec form with an absolute binary path: override ENTRYPOINT, run the command verbatim. + command = []string(req.Command) + args = nil + case len(req.Command) > 1: + // Multi-arg but not an absolute path: treat as args to the image ENTRYPOINT (e.g. a + // shell-wrapper entrypoint that execs "$@" and needs update-ca-certificates to run first). command = nil args = []string(req.Command) - } else if len(req.Command) == 1 && req.Command[0] != "" { + case len(req.Command) == 1 && req.Command[0] != "": // Single string: run via bash -c (no image entrypoint) command = []string{"/bin/bash", "-c"} args = []string{req.Command[0]}