floci-io/floci · error · IllegalStateException
Hook script timed out after %d seconds: %s
Error message
Hook script timed out after %d seconds: %s
What it means
Thrown when an init-hook script does not finish within initHooksConfig.timeoutSeconds(). Floci waits with process.waitFor(timeout, SECONDS), logs that the timeout was exceeded, attempts graceful termination via terminateProcess, and throws IllegalStateException with the configured timeout value and script name. A finally block force-destroys the process if it is still alive.
Source
Thrown at src/main/java/io/github/hectorvent/floci/lifecycle/inithook/HookScriptExecutor.java:53
void run(final Process process, final String scriptFileName) throws InterruptedException {
final int exitCode = waitForProcessExitCode(process, scriptFileName);
if (exitCode != 0) {
final String message = String.format("Hook script failed: %s exited with code %d", scriptFileName, exitCode);
throw new IllegalStateException(message);
}
}
private int waitForProcessExitCode(final Process process, final String scriptFileName) throws InterruptedException {
try {
final long timeoutSeconds = initHooksConfig.timeoutSeconds();
final boolean finished = process.waitFor(timeoutSeconds, TimeUnit.SECONDS);
if (!finished) {
LOG.debugv("Hook script exceeded timeout of {0} seconds, terminating process: {1}", timeoutSeconds, scriptFileName);
terminateProcess(process, scriptFileName);
final String message = String.format("Hook script timed out after %d seconds: %s", timeoutSeconds, scriptFileName);
throw new IllegalStateException(message);
}
return process.exitValue();
} finally {
if (process.isAlive()) {
LOG.debugv("Hook script process still alive during cleanup, forcing termination: {0}", scriptFileName);
process.destroyForcibly();
}
}
}
private void terminateProcess(final Process process, final String scriptFileName) throws InterruptedException {
// Try a graceful shutdown first, then force termination if the process does not exit in time.
process.destroy();
if (process.isAlive()) {
final long shutdownGracePeriodSeconds = initHooksConfig.shutdownGracePeriodSeconds();
final boolean terminatedGracefully = process.waitFor(shutdownGracePeriodSeconds, TimeUnit.SECONDS);
if (!terminatedGracefully) {View on GitHub (pinned to 62ff490619)
Solutions
- Reproduce locally by timing the script: time sh script.sh — find the hanging command
- Add explicit timeouts to every network command in the hook (curl --max-time 10, wget -T 10, timeout 30 cmd)
- Ensure the script never reads stdin; redirect stdin from /dev/null if needed
- If the script legitimately needs longer, raise the init-hooks timeoutSeconds in Floci configuration (floci.* init hooks config in application.yml / FLOCI_* env vars)
- Bound any retry loop in the script with a maximum attempt count and total wall-clock budget below the configured timeout
Example fix
# before until curl -s http://deps.local/ready; do sleep 1; done # after for i in $(seq 1 30); do curl -sf --max-time 5 http://deps.local/ready && exit 0 sleep 1 done echo "dependency not ready in 30s" >&2 exit 1
Defensive patterns
Strategy: validation
Validate before calling
# time each hook; anything near the configured timeout is a latent failure timeout 30 sh hooks/01-setup.sh; echo "exit=$?" # 124 means it would time out
Prevention
- Never let a hook read stdin; redirect '< /dev/null' where relevant
- Bound all waits/retries inside hooks to well under the configured timeoutSeconds
- Raise floci init-hooks timeoutSeconds only after proving the script genuinely needs longer
When it happens
Trigger: A hook script blocks forever: waiting on a network resource that never responds (curl without --max-time), a long sleep, a REPL prompt, reading stdin (the process inherits parent I/O), or a retry loop with no bound. Also a timeoutSeconds configuration set lower than the script legitimately needs.
Common situations: Scripts ported from interactive manuals that pause for input; curl/wget without timeouts in flaky networks; DNS hangs in containers; a script that waits for a containerized dependency (RDS/Lambda image pull) whose startup exceeds the configured Floci hook timeout.
Understand the failure class
- Timeouts: ETIMEDOUT, deadlines, and hung requests — what actually expires when a request times out.
Related errors
- Hook script failed: %s exited with code %d
- Boot hook execution interrupted
- Boot hook execution failed
- floci.storage.efs owner-uid and owner-gid must be set togeth
- Persistent storage path '" + root.toAbsolutePath() + "' is n
AI-assisted analysis of floci-io/floci@62ff490619 (2026-08-14).
Data as JSON: /api/errors/1362ebd2299168af.
Report an issue: GitHub.