{"record":{"id":"a551431579c251f3","repo":"docker/cli","slug":"exec-id-empty","errorCode":null,"errorMessage":"exec ID empty","messagePattern":"exec ID empty","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cli/command/container/exec.go","lineNumber":118,"sourceCode":"\tif _, err := apiClient.ContainerInspect(ctx, containerIDorName, client.ContainerInspectOptions{}); err != nil {\n\t\treturn err\n\t}\n\tif !options.Detach {\n\t\tif err := dockerCLI.In().CheckTty(execOptions.AttachStdin, execOptions.TTY); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tfillConsoleSize(execOptions, dockerCLI)\n\n\tresponse, err := apiClient.ExecCreate(ctx, containerIDorName, *execOptions)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\texecID := response.ID\n\tif execID == \"\" {\n\t\treturn errors.New(\"exec ID empty\")\n\t}\n\n\tif options.Detach {\n\t\t_, err := apiClient.ExecStart(ctx, execID, client.ExecStartOptions{\n\t\t\tDetach:      options.Detach,\n\t\t\tTTY:         execOptions.TTY,\n\t\t\tConsoleSize: client.ConsoleSize{Height: execOptions.ConsoleSize.Height, Width: execOptions.ConsoleSize.Width},\n\t\t})\n\t\treturn err\n\t}\n\treturn interactiveExec(ctx, dockerCLI, execOptions, execID)\n}\n\nfunc fillConsoleSize(execOptions *client.ExecCreateOptions, dockerCli command.Cli) {\n\tif execOptions.TTY {\n\t\theight, width := dockerCli.Out().GetTtySize()\n\t\texecOptions.ConsoleSize = client.ConsoleSize{Height: height, Width: width}\n\t}","sourceCodeStart":100,"sourceCodeEnd":136,"githubUrl":"https://github.com/docker/cli/blob/4f84911bfe8811e9b028e4b1fee8e7510be79387/cli/command/container/exec.go#L100-L136","documentation":"Returned after a successful ExecCreate API call when the server response contains an empty ID string (exec.go:116-119). This is a defensive guard against a broken daemon response rather than a user-input error; if the ID were used, subsequent ExecStart/attach calls would fail in a more confusing way, and the exec resource could leak.","triggerScenarios":"Calling `docker exec` (or the client ExecCreate/ContainerExecCreate path) against a daemon that returns 200 OK but omits or blanks the ID field in the JSON response. Most often a proxy, API shim, or a daemon build with a bug in the exec creation handler.","commonSituations":"Using a non-standard engine or API proxy (e.g. a custom Moby fork, a buggy remote API gateway) that does not populate the exec ID; hitting a daemon version mismatch between client and server; rare transient corruption of the API response.","solutions":["Retry the exec command once to rule out a transient daemon hiccup.","Check the daemon version with `docker version` and upgrade/align the client and server.","If behind a proxy or remote DOCKER_HOST, inspect the raw API response for the missing ID field.","Report a daemon bug if the issue persists against stock moby/moby."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"// After ExecCreate, guard the empty-ID case before proceeding.\nresp, err := cli.Client().ExecCreate(ctx, id, *execCfg)\nif err != nil { return err }\nif resp.ID == \"\" {\n    // surface a clear error and optionally retry once\n    return fmt.Errorf(\"daemon returned empty exec id for %q\", id)\n}","preventionTips":["Always check the returned ID for emptiness, mirroring the CLI's own guard.","Keep client and daemon versions aligned via `docker version`.","Avoid API shims/proxies that may strip the ID field."],"tags":["docker-cli","exec","daemon-response","defensive-guard"],"backgroundTag":null,"analyzedSha":"4f84911bfe8811e9b028e4b1fee8e7510be79387","analyzedAt":"2026-08-07T12:15:29.814Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}