spring-projects/spring-boot · error · SocketException

Socket input is shutdown

Error message

Socket input is shutdown

What it means

The third state check in UnixDomainSocket.getInputStream: if isInputShutdown() is true, throw SocketException('Socket input is shutdown'). This mirrors java.net.Socket.shutdownInput() semantics — a half-close for the read direction. Once shutdownInput() has been called, the input stream cannot be obtained again on the same socket.

Solutions

  1. Do not call shutdownInput() if further reads are needed on this socket.
  2. Open a new socket (UnixDomainSocket.get(path)) for the next read.

Example fix

// before
socket.shutdownInput();
socket.getInputStream().read(); // throws "Socket input is shutdown"
// after: open a fresh socket for the next read
Socket next = UnixDomainSocket.get(path);
next.getInputStream().read();
Defensive patterns

Strategy: validation

Validate before calling

// Guard before obtaining a stream
if (socket.isInputShutdown()) {
    socket = UnixDomainSocket.get(path); // reopen for a fresh input stream
}
InputStream in = socket.getInputStream();

Try / catch

try {
    socket.getInputStream();
} catch (java.net.SocketException ex) {
    if ("Socket input is shutdown".equals(ex.getMessage())) {
        socket = UnixDomainSocket.get(path); // reopen and retry once
    } else throw ex;
}

Prevention

When it happens

Trigger: getInputStream() is called after shutdownInput() was invoked on the socket (half-close for reading).

Common situations: A protocol layer that calls shutdownInput() after sending a request and then tries to read a response; reuse of a half-closed socket for a second request; test code invoking shutdownInput().

Related errors


AI-assisted analysis of spring-projects/spring-boot@270dfe353f (2026-08-11). Data as JSON: /api/errors/69195dee725dd1a0. Report an issue: GitHub.

Appendix: source

Thrown at buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/socket/UnixDomainSocket.java:65

	private final SocketAddress socketAddress;

	private final SocketChannel socketChannel;

	private UnixDomainSocket(String path) throws IOException {
		this.socketAddress = UnixDomainSocketAddress.of(path);
		this.socketChannel = SocketChannel.open(this.socketAddress);
	}

	@Override
	public InputStream getInputStream() throws IOException {
		if (isClosed()) {
			throw new SocketException("Socket is closed");
		}
		if (!isConnected()) {
			throw new SocketException("Socket is not connected");
		}
		if (isInputShutdown()) {
			throw new SocketException("Socket input is shutdown");
		}

		return Channels.newInputStream(this.socketChannel);
	}

	@Override
	public OutputStream getOutputStream() throws IOException {
		if (isClosed()) {
			throw new SocketException("Socket is closed");
		}
		if (!isConnected()) {
			throw new SocketException("Socket is not connected");
		}
		if (isOutputShutdown()) {
			throw new SocketException("Socket output is shutdown");
		}

		return Channels.newOutputStream(this.socketChannel);

View on GitHub (pinned to 270dfe353f)