{"record":{"id":"d2fa2d34c52a04a0","repo":"kestra-io/kestra","slug":"unable-to-get-random-port","errorCode":null,"errorMessage":"Unable to get random port","messagePattern":"Unable to get random port","errorType":"exception","errorClass":"PebbleException","httpStatus":null,"severity":"error","filePath":"core/src/main/java/io/kestra/core/runners/pebble/functions/RandomPortFunction.java","lineNumber":20,"sourceCode":"\nimport java.io.IOException;\nimport java.net.ServerSocket;\nimport java.util.List;\nimport java.util.Map;\n\nimport io.pebbletemplates.pebble.error.PebbleException;\nimport io.pebbletemplates.pebble.template.EvaluationContext;\nimport io.pebbletemplates.pebble.template.PebbleTemplate;\n\npublic class RandomPortFunction implements KestraFunction {\n    public static final String NAME = \"randomPort\";\n\n    @Override\n    public Object execute(Map<String, Object> args, PebbleTemplate self, EvaluationContext context, int lineNumber) {\n        try (ServerSocket tempSocket = new ServerSocket(0)) {\n            return tempSocket.getLocalPort();\n        } catch (IOException e) {\n            throw new PebbleException(\n                e,\n                \"Unable to get random port\",\n                lineNumber,\n                self.getName()\n            );\n        }\n    }\n\n    @Override\n    public List<String> getArgumentNames() {\n        return List.of();\n    }\n\n    @Override\n    public Map<String, String> getArgumentDefaults() {\n        return Map.of();\n    }\n}","sourceCodeStart":2,"sourceCodeEnd":38,"githubUrl":"https://github.com/kestra-io/kestra/blob/823fada9274c4f9c251ea0a516460a4f7d958032/core/src/main/java/io/kestra/core/runners/pebble/functions/RandomPortFunction.java#L2-L38","documentation":"The randomPort() Pebble function opens a ServerSocket on port 0 to let the OS assign an ephemeral port, then returns it. It throws a PebbleException wrapping the original IOException when the socket cannot be created. This is a thin JVM-level operation: the function takes no arguments and simply asks the OS for a free TCP port.","triggerScenarios":"Calling {{ randomPort() }} in a Pebble expression when the OS refuses to open a new socket — e.g., the process has exhausted its file-descriptor limit (ulimit -n), a SecurityManager denies ServerSocket creation, the network stack is unavailable (container with no networking), or all ephemeral ports are in use.","commonSituations":"Running Kestra in a locked-down container with a very low ulimit or seccomp profile that blocks socket creation. CI runners or sandboxed workers where networking is disabled. A flow that calls randomPort() in a tight loop across many parallel task runs, exhausting ephemeral ports (TIME_WAIT storm).","solutions":["Check the OS file-descriptor and socket limits (ulimit -n, sysctl net.ipv4.ip_local_port_range) and raise them if the error occurs under load.","Avoid calling randomPort() repeatedly in parallel tasks; cache the result in a flow variable or input and pass it down.","If running in a sandboxed container, ensure the seccomp/AppArmor profile permits the socket(2) syscall.","Fall back to a static port assignment from flow inputs or environment variables instead of relying on dynamic allocation."],"exampleFix":"# before (exhausts ephemeral ports under parallel load)\nid: many-parallel-tasks\ntasks:\n  - id: each\n    type: io.kestra.plugin.core.flow.ForEach\n    value: \"{{ range(1, 100) }}\"\n    tasks:\n      - id: use_port\n        type: io.kestra.plugin.scripts.shell.Commands\n        commands:\n          - \"echo {{ randomPort() }}\"\n\n# after (allocate once, reuse)\nid: allocate-port-once\ninputs:\n  - id: port\n    type: INT\n    defaults: \"{{ randomPort() }}\"\ntasks:\n  - id: use_port\n    type: io.kestra.plugin.scripts.shell.Commands\n    commands:\n      - \"echo {{ inputs.port }}\"","handlingStrategy":"retry","validationCode":"# Before calling randomPort() in a high-throughput flow, verify OS socket limits are healthy:\n# (run on the Kestra worker host)\n# ulimit -n          # check file descriptor limit\n# sysctl net.ipv4.ip_local_port_range  # check ephemeral port range\n# If calling from a script task, pre-check socket availability:\n# python3 -c \"import socket; s=socket.socket(); s.bind(('',0)); print(s.getsockname()[1]); s.close()\"","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Cache the randomPort() result in a flow input rather than calling it in every parallel task.","Monitor worker file-descriptor usage and ephemeral port exhaustion under load.","Ensure container security profiles permit socket creation.","Prefer static port assignment from configuration when determinism is needed."],"tags":["network","ports","pebble","randomport","ephemeral-port"],"backgroundTag":null,"analyzedSha":"823fada9274c4f9c251ea0a516460a4f7d958032","analyzedAt":"2026-08-14T06:15:17.947Z","schemaVersion":2},"datasetVersion":"2026-08-14T10:17:34.591Z"}