pentaho/pentaho-kettle · error · SshTimeoutException

Command execution timed out after

Error message

Command execution timed out after ${timeoutMs}ms

What it means

exec(command, timeoutMs) polls the channel's exit status and, when the wait window elapses before the remote command completes, throws SshTimeoutException('Command execution timed out after Nms'). The command may still be running remotely; the client simply stopped waiting.

Solutions

  1. Increase commandTimeoutMillis to exceed the command's worst-case duration
  2. Fix the remote command to run non-interactively (no prompts, redirect stdin)
  3. Run long jobs with nohup/background on the remote host and poll for completion
  4. Verify the command is not blocked waiting for input (test interactively)
  5. Break the work into smaller commands within the timeout window

Example fix

// before
ExecResult r = conn.exec( "/opt/etl/run-all.sh", 30000 ); // 30s, job takes minutes
// after
ExecResult r = conn.exec( "/opt/etl/run-all.sh", 1800000 ); // 30min budget
// or: nohup /opt/etl/run-all.sh > /tmp/etl.log 2>&1 & then poll
Defensive patterns

Strategy: try-catch

Validate before calling

// estimate: ensure timeout exceeds worst-case command duration
long expectedMaxMillis = estimateCommandDuration( command );
if ( config.getCommandTimeoutMillis() < expectedMaxMillis ) {
  log.warn( "Command timeout {}ms is below expected duration {}ms", config.getCommandTimeoutMillis(), expectedMaxMillis );
}

Try / catch

try { result = conn.exec( cmd, timeoutMs ); }
catch ( SshTimeoutException e ) {
  log.warn( "Command exceeded {}ms; it may still be running remotely", timeoutMs );
  // optionally reconnect and kill/check the remote process before retrying
}

Prevention

When it happens

Trigger: exec() is called with commandTimeoutMillis > 0 and the remote command does not produce an exit status within that period — long-running scripts, hung remote processes, or output waiting on a TTY prompt.

Common situations: Running backups/ETL scripts that exceed the default command timeout; remote command waiting on a password/passphrase prompt; remote host under load.

Understand the failure class

Background: Request timed out: what client-side request timeouts mean across libraries (Request timed out, TIMED_OUT, APITimeoutError) — this error's family across 39 libraries.

Related errors


AI-assisted analysis of pentaho/pentaho-kettle@f3058517a1 (2026-09-13). Data as JSON: /api/errors/b147aa3665003582. Report an issue: GitHub.

Appendix: source

Thrown at engine/src/main/java/org/pentaho/di/core/ssh/mina/MinaSshConnection.java:460

        }

        // Wait for the command to complete and exit status to be available
        Set<ClientChannelEvent> events = ch.waitFor(
          EnumSet.of( ClientChannelEvent.CLOSED ), timeoutMs );

        // Give a bit more time for exit status to be set if the channel closed successfully
        if ( events.contains( ClientChannelEvent.CLOSED ) ) {
          // Try to get exit status with a short additional wait
          Integer ex = ch.getExitStatus();
          if ( ex == null ) {
            // Wait a bit more for exit status to be set
            Thread.sleep( 100 );
            ex = ch.getExitStatus();
          }
          exit = ex == null ? -1 : ex;
        } else {
          // Timeout occurred
          throw new SshTimeoutException( "Command execution timed out after " + timeoutMs + "ms" );
        }
      }
      String outStr = stdout.toString( StandardCharsets.UTF_8 );
      String errStr = stderr.toString( StandardCharsets.UTF_8 );
      return new ExecResult( outStr, errStr, outStr + errStr, exit, exit != 0 );
    } catch ( SshTimeoutException e ) {
      throw e; // Re-throw timeout exceptions as-is
    } catch ( InterruptedException e ) {
      Thread.currentThread().interrupt(); // Restore interrupted status
      throw new SshConnectionException( "Command execution was interrupted", e );
    } catch ( Exception e ) {
      throw new SshConnectionException( "Failed to execute command: " + command, e );
    }
  }

  @Override
  public ExecResult exec( String command ) throws SshConnectionException {
    return exec( command, config.getCommandTimeoutMillis() );

View on GitHub (pinned to f3058517a1)