stanfordnlp/CoreNLP · error · IllegalArgumentException
Must capture one of stderr or stdout
Error message
Must capture one of stderr or stdout
What it means
RedwoodConfiguration.restore(OutputStream) throws IllegalArgumentException when the passed stream is neither System.out nor System.err. restore() exists solely to undo Redwood's capture of the standard system streams, so only those two streams are meaningful arguments.
Solutions
- Pass exactly System.out or System.err — the same object references Redwood captured
- Restore before calling System.setOut()/setErr() so the identity checks still match
- Use RedwoodConfiguration.None() or Redwood.stop() to disable Redwood entirely instead of restore()
- To detach a custom stream, just stop using it / close it; restore() only applies to the system streams
Example fix
// before
PrintStream mine = new PrintStream(new FileOutputStream("log.txt"));
config.restore(mine); // throws
// after
config.restore(System.out); // or System.err — must be the real system stream Defensive patterns
Strategy: type-guard
Validate before calling
if (stream != System.out && stream != System.err) {
throw new IllegalArgumentException("restore() accepts only System.out or System.err");
}
config.restore(stream); Type guard
static boolean isSystemStream(OutputStream s) {
return s == System.out || s == System.err;
} Try / catch
try {
config.restore(System.out);
} catch (IllegalArgumentException e) {
log.warn("restore() needs System.out or System.err: {}", e.getMessage());
} Prevention
- Only pass System.out or System.err object references to restore()
- Call restore() before any System.setOut()/setErr() redirection replaces the stream identity
- Use RedwoodConfiguration.None() or Redwood.stop() for full shutdown instead of restore()
- Remember restore() undoes capture of system streams, not arbitrary streams
When it happens
Trigger: Calling restore(stream) with any other OutputStream: a FileOutputStream, ByteArrayOutputStream, a wrapped System.out (System.setOut(new PrintStream(...)) replaced the original so the reference no longer equals System.out), or null.
Common situations: Trying to restore a redirected stdout after System.setOut() was called (the field no longer aliases the original stream); passing a log file stream expecting restore to detach it; copying code and substituting a custom stream.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- Called remove() before any elements returned
- Cannot modify Redwood when within a track
- Cannot nest Redwood threaded environments
- OutputHandler received endTrack() without matching…
- Attempted to replace a root node with more than one node…
AI-assisted analysis of stanfordnlp/CoreNLP@1b7edd19c4 (2026-09-10).
Data as JSON: /api/errors/cb4397f7d81eb411.
Report an issue: GitHub.
Appendix: source
Thrown at src/edu/stanford/nlp/util/logging/RedwoodConfiguration.java:85
public RedwoodConfiguration capture(final OutputStream stream) {
// Capture the stream
if (stream == System.out) {
tasks.add(() -> Redwood.captureSystemStreams(true, Redwood.realSysErr == System.err));
} else if (stream == System.err) {
tasks.add(() -> Redwood.captureSystemStreams(Redwood.realSysOut == System.out, true));
} else {
throw new IllegalArgumentException("Must capture one of stderr or stdout");
}
return this;
}
public RedwoodConfiguration restore(final OutputStream stream) {
if (stream == System.out) {
tasks.add(() -> Redwood.captureSystemStreams(false, Redwood.realSysErr == System.err));
} else if (stream == System.err) {
tasks.add(() -> Redwood.captureSystemStreams(Redwood.realSysOut == System.out, false));
} else {
throw new IllegalArgumentException("Must capture one of stderr or stdout");
}
return this;
}
public RedwoodConfiguration listenOnChannels(Consumer<Redwood.Record> listener, Object... channels) {
return this.handlers(
Handlers.chain(new FilterHandler(Collections.singletonList(new LogFilter() {
Set<Object> matchAgainst = new HashSet<>(Arrays.asList(channels));
@Override
public boolean matches(Redwood.Record message) {
for (Object channel : message.channels()) {
if (matchAgainst.contains(channel)) {
return true;
}
}
return false;View on GitHub (pinned to 1b7edd19c4)