kestra-io/kestra · error · PebbleException
Unable to get random port
Error message
Unable to get random port
What it means
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.
Source
Thrown at core/src/main/java/io/kestra/core/runners/pebble/functions/RandomPortFunction.java:20
import java.io.IOException;
import java.net.ServerSocket;
import java.util.List;
import java.util.Map;
import io.pebbletemplates.pebble.error.PebbleException;
import io.pebbletemplates.pebble.template.EvaluationContext;
import io.pebbletemplates.pebble.template.PebbleTemplate;
public class RandomPortFunction implements KestraFunction {
public static final String NAME = "randomPort";
@Override
public Object execute(Map<String, Object> args, PebbleTemplate self, EvaluationContext context, int lineNumber) {
try (ServerSocket tempSocket = new ServerSocket(0)) {
return tempSocket.getLocalPort();
} catch (IOException e) {
throw new PebbleException(
e,
"Unable to get random port",
lineNumber,
self.getName()
);
}
}
@Override
public List<String> getArgumentNames() {
return List.of();
}
@Override
public Map<String, String> getArgumentDefaults() {
return Map.of();
}
}View on GitHub (pinned to 823fada927)
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.
Example fix
# before (exhausts ephemeral ports under parallel load)
id: many-parallel-tasks
tasks:
- id: each
type: io.kestra.plugin.core.flow.ForEach
value: "{{ range(1, 100) }}"
tasks:
- id: use_port
type: io.kestra.plugin.scripts.shell.Commands
commands:
- "echo {{ randomPort() }}"
# after (allocate once, reuse)
id: allocate-port-once
inputs:
- id: port
type: INT
defaults: "{{ randomPort() }}"
tasks:
- id: use_port
type: io.kestra.plugin.scripts.shell.Commands
commands:
- "echo {{ inputs.port }}" Defensive patterns
Strategy: retry
Validate before calling
# Before calling randomPort() in a high-throughput flow, verify OS socket limits are healthy:
# (run on the Kestra worker host)
# ulimit -n # check file descriptor limit
# sysctl net.ipv4.ip_local_port_range # check ephemeral port range
# If calling from a script task, pre-check socket availability:
# python3 -c "import socket; s=socket.socket(); s.bind(('',0)); print(s.getsockname()[1]); s.close()" Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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).
Related errors
- Failed to execute HTTP Request, server respond with status {
- Failed to execute HTTP request
- Too many rendering attempts
- The '%s' filter expects an integer as argument 'amount'.
- The '%s' filter expects a positive integer >=0 as argument '
AI-assisted analysis of kestra-io/kestra@823fada927 (2026-08-14).
Data as JSON: /api/errors/d2fa2d34c52a04a0.
Report an issue: GitHub.