jenkinsci/jenkins · error · IOException

Can not call launchChannel on a dummy launcher.

Error message

Can not call launchChannel on a dummy launcher.

What it means

DummyLauncher.launchChannel throws IOException because it has no remote channel to connect to — it exists as a type-compliant placeholder Launcher. launchChannel is used to start a remote process and obtain its Channel for remoting. Since DummyLauncher has no underlying transport, this always fails.

Source

Thrown at core/src/main/java/hudson/Launcher.java:1078

            };
        }
    }

    @Restricted(NoExternalUse.class)
    public static class DummyLauncher extends Launcher {

        public DummyLauncher(@NonNull TaskListener listener) {
            super(listener, null);
        }

        @Override
        public Proc launch(ProcStarter starter) throws IOException {
            throw new IOException("Can not call launch on a dummy launcher.");
        }

        @Override
        public Channel launchChannel(String[] cmd, OutputStream out, FilePath workDir, Map<String, String> envVars) throws IOException, InterruptedException {
            throw new IOException("Can not call launchChannel on a dummy launcher.");
        }

        @Override
        public void kill(Map<String, String> modelEnvVars) throws IOException, InterruptedException {
            // Kill method should do nothing.
        }
    }


    /**
     * Launches processes remotely by using the given channel.
     */
    public static class RemoteLauncher extends Launcher {
        private final boolean isUnix;

        public RemoteLauncher(@NonNull TaskListener listener, @NonNull VirtualChannel channel, boolean isUnix) {
            super(listener, channel);
            this.isUnix = isUnix;

View on GitHub (pinned to 2e228ff40b)

Solutions

  1. Obtain a real Launcher from a Computer that has an active channel before calling launchChannel.
  2. In tests, use a real Channel/Launcher setup or mock launchChannel appropriately.
  3. Guard with an instanceof check against Launcher.DummyLauncher.

Example fix

// before
Channel ch = launcher.launchChannel(cmd, out, workDir, env);

// after
if (launcher instanceof Launcher.DummyLauncher) {
    throw new IllegalStateException("Cannot launch channel without a real agent.");
}
Channel ch = launcher.launchChannel(cmd, out, workDir, env);
Defensive patterns

Strategy: type-guard

Validate before calling

if (launcher instanceof Launcher.DummyLauncher) {
    throw new IllegalStateException("Cannot launch channel: no real agent.");
}

Type guard

public static boolean canLaunchChannel(Launcher l) {
    return !(l instanceof Launcher.DummyLauncher);
}

Try / catch

try {
    Channel ch = launcher.launchChannel(cmd, out, workDir, env);
} catch (IOException e) {
    if (e.getMessage().contains("dummy launcher")) {
        throw new IllegalStateException("No channel available; provide a real Launcher", e);
    }
    throw e;
}

Prevention

When it happens

Trigger: Code calls Launcher.launchChannel(String[], OutputStream, FilePath, Map) on a DummyLauncher — typically during remoting setup or a plugin that tries to establish a channel to a process that doesn't exist.

Common situations: Plugin code or pipeline infrastructure attempting to establish a remoting channel in a context where the Launcher is a DummyLauncher (controller-only execution, test harness without a real agent).

Related errors


AI-assisted analysis of jenkinsci/jenkins@2e228ff40b (2026-08-14). Data as JSON: /api/errors/8784a83c4a9c3a1e. Report an issue: GitHub.