alibaba/arthas · error · IllegalStateException

Cannot write to standard output when {}

Error message

Cannot write to standard output when {}

What it means

ArthasStreamObserverImpl.appendResult() throws IllegalStateException when the backing process is not in ExecStatus.RUNNING state. Results can only be appended to the output stream while the command process is actively running; appending after it has terminated, finished, or been cancelled corrupts the result pipeline.

Source

Thrown at labs/arthas-grpc-web-proxy/src/main/java/com/taobao/arthas/grpcweb/grpc/observer/impl/ArthasStreamObserverImpl.java:154

    }

    @Override
    public void end(int statusCode, String message) {
        terminate(statusCode, message);
    }


    @Override
    public ArthasStreamObserver write(String msg) {
        ResponseBody result = ResponseBody.newBuilder().setStringValue(msg).build();
        onNext((T) result);
        return this;
    }

    @Override
    public void appendResult(ResultModel result) {
        if (process.status() != ExecStatus.RUNNING) {
            throw new IllegalStateException(
                    "Cannot write to standard output when " + process.status().name().toLowerCase());
        }
        result.setJobId(jobId);
        if (resultDistributor != null) {
            resultDistributor.appendResult(result);
        }
    }
    @Override
    public int getJobId() {
        return jobId;
    }

    @Override
    public Object getRequestModel() {
        return requestModel;
    }

    @Override

View on GitHub (pinned to 21cf2e9ba5)

Solutions

  1. Ensure all result-appending completes before calling end()/terminate() on the process.
  2. Guard appendResult calls with a check: if (process.status() == ExecStatus.RUNNING) before appending.
  3. Fix the race by synchronizing result emission with process lifecycle transitions.

Example fix

// before: async callback appends after termination
process.end(0);
observer.appendResult(lateResult); // throws

// after: append before ending, or guard
if (process.status() == ExecStatus.RUNNING) {
    observer.appendResult(lateResult);
}
process.end(0);
Defensive patterns

Strategy: validation

Validate before calling

if (process.status() == ExecStatus.RUNNING) {
    observer.appendResult(result);
} else {
    log.debug("Skipping appendResult — process is {}", process.status());
}

Type guard

import com.taobao.arthas.core.shell.system.ExecStatus;
public boolean isProcessRunning(Process process) {
    return process != null && process.status() == ExecStatus.RUNNING;
}

Try / catch

try {
    observer.appendResult(result);
} catch (IllegalStateException e) {
    if (e.getMessage().contains("Cannot write to standard output")) {
        // process already ended — buffer or drop the result
        log.warn("Dropped result, process not running: {}", process.status());
    } else { throw e; }
}

Prevention

When it happens

Trigger: Calling appendResult(resultModel) after process.status() has transitioned to TERMINATED, FINISHED, or any non-RUNNING state — e.g. writing results from an async callback that fires after the process ended.

Common situations: A background thread or gRPC callback tries to push results after the command process already terminated; a race between process termination and a late result emission; explicit end() was called before all results were appended.

Related errors


AI-assisted analysis of alibaba/arthas@21cf2e9ba5 (2026-08-14). Data as JSON: /api/errors/e175ea5ac6d726e1. Report an issue: GitHub.