16

In catalina.out log of my Tomcat7 I get an error caused by a third-party library that starts with:

INFO: An error occurred in processing while on a non-container thread. The connection will be closed immediately
java.net.SocketException: Broken pipe
        at java.net.SocketOutputStream.socketWrite0(Native Method)
        at java.net.SocketOutputStream.socketWrite(SocketOutputStream.java:113)

What does it really mean that the error occurred in a non-container thread?

I tried to get a similar log message by throwing an a exception from a new Thread spawned from my application code with something like that:

new Thread(){
    @Override
    public void run() {
        Integer.parseInt("boom");
    }
}.start();

but it results in

Exception in thread "Thread-28" java.lang.NumberFormatException: For input string: "boom"
    at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
    at java.lang.Integer.parseInt(Integer.java:492)
    at java.lang.Integer.parseInt(Integer.java:527)
    at ...

So the question is: What does it mean when I see a log like the one quoted on the top? What does it mean that the error occurs in a non-container thread? How can I recreate that?

TMG
  • 2,620
  • 1
  • 17
  • 40

2 Answers2

8

What does it really mean that the error occurred in a non-container thread?

This happens when you are using JSP 3.0+ asynchronous request processing.

In asynchronous mode, the client request is received by a "container" thread that calls the Servlet's service() method. This method (or one of the subsidiary doXxxx methods) calls startAsync() which creates a Runnable for the request and dispatches it to an Executor. This executor then processes the requests on ("non-container") worker threads.

(A more detailed explanation of what is going on in async mode, complete with an example, can be found here.)

Anyhow, the "INFO:" message is simply saying that the original exception was thrown on the stack of one of the Executor's worker threads. It is produced when Tomcat decides to dispatch the failed request back to a a container thread so that the request cleanup can be performed.

In your example, I suspect that the original SocketException was caused by the request processing taking so long that the client (e.g. the user's browser) timed out the request and closed the socket. Some time later, your server tried to write the response and that failed because the connection had been closed.

How can I recreate that?

I am guessing, but you should be able to reproduce that "INFO:" message by throwing an exception in the Runnable's run() method. You have to use async mode of course.

Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
6

First Issue:

INFO: An error occurred in processing while on a non-container thread. The connection will be closed immediately

Ans:

The async.Stockticker thread crashed due to a non handled ISE. This explains the behaviour. The exception is logged to the console only. It is not logged into Tomcat log files. It is a bug with error handling for Tomcat. It is not a regression from recent changes. It is reproducible with Tomcat 7.0.59.

It is already fixed in trunk 8.0.x (for 8.0.21 onwards) and 7.0.x (for 7.0.60 onwards). So you can upgrade your tomcat version. Then this info message will not be shown.

Resource Link:

Bug 57683 - Crash of stockticket async example caused by an aborted client request



Second Issue:

java.net.SocketException: Broken pipe

Solution-1:

This problem actually occurs when we missed to close the connections like URLConnection and close various open streams. I want to share an example

Before:

OutputStream out = new BufferedOutputStream(urlConnection.getOutputStream());
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(out));
bw.write("Lorem ipsum...");
out.close();

After:

OutputStream os = urlConnection.getOutputStream();
OutputStream out = new BufferedOutputStream(os);
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(out));
bw.write("Lorem ipsum...");
bw.close(); //This is must. If you miss to close, then "java.net.SocketException: Broken pipe" error comes
out.close();
os.close(); 

Solution-2:

When we want to load testing in our app server, sometimes this error occurs.

The data takes a long time to be generated and the load testing tool does not wait for the large amounts of data long enough then it closes the connection. Actually low memory caused the application to close the receiving socket or indeed exit altogether, with the same effect.

If we add additional memory to our JVM, then it resolved the issue.

Solution-3:

As @EJP suggested,

This is caused by writing to a connection when the other end has already closed it.

So you have a poorly defined or implemented application protocol. if this is happening there is something wrong with your application protocol specification or implementation, most probably that you don't even have connection.

If the server side HTTP application is getting Broken Pipe exceptions it just means the client browser has exited/gone to another page/timed out/gone back in the history/whatever. Just forget about it.

Resource Link:

  1. How to fix java.net.SocketException: Broken pipe?
  2. Why a "java.net.SocketException: Broken pipe" will occur?

If you want to reproduce this error, then this tutorial may help you.



Third Issue:

Exception in thread "Thread-28" java.lang.NumberFormatException: For input string: "boom"

This error occurs when you tried to convert/parse alphabetic string to interger. It is normal java error NumberFormatException.



UPDATE:

As you have wanted to know that in which cases Tomcat decides to log that additional message when catching exception that was thrown out of an application. So I am sharing briefly.

For making a clear conception of "INFO: An error occurred in processing while on a non-container thread. The connection will be closed immediately java.net.SocketException: Broken pipe", First I want to share with you that it is socket related issue. There are 6 SocketEvent in tomcat. They are OPEN_READ, OPEN_WRITE, STOP, TIMEOUT, DISCONNECT and ERROR. These occur per socket that require further processing by the container. Usually these events are triggered by the socket implementation but they may be triggered by the container also.

Socket Event "ERROR":

An error has occurred on a non-container thread and processing needs to return to the container for any necessary clean-up. Examples of where this is used include:

  • by NIO2 to signal the failure of a completion handler
  • by the container to signal an I/O error on a non-container thread during Servlet 3.0 asynchronous processing.

When this error occurs and INFO message is shown in TOMCAT?

This is the code snapshot where the info message comes.

  /**
     * Update the current error state to the new error state if the new error
     * state is more severe than the current error state.
     * @param errorState The error status details
     * @param t The error which occurred
     */
    protected void setErrorState(ErrorState errorState, Throwable t) {
        boolean blockIo = this.errorState.isIoAllowed() && !errorState.isIoAllowed();
        this.errorState = this.errorState.getMostSevere(errorState);
        if (blockIo && !ContainerThreadMarker.isContainerThread() && isAsync()) {
            // The error occurred on a non-container thread during async
            // processing which means not all of the necessary clean-up will
            // have been completed. Dispatch to a container thread to do the
            // clean-up. Need to do it this way to ensure that all the necessary
            // clean-up is performed.
            if (response.getStatus() < 400) {
                response.setStatus(500);
            }
            getLog().info(sm.getString("abstractProcessor.nonContainerThreadError"), t);  // This section gives the INFO message "INFO: An error occurred in processing while on a non-container thread. The connection will be closed immediately"
            socketWrapper.processSocket(SocketEvent.ERROR, true);
        }
    }

How DEADLOCK may occur?

When a request uses a sequence of multiple start(); dispatch() with non-container threads it is possible for a previous dispatch() to interfere with a following start(). This lock prevents that from happening. It is a dedicated object as user code may lock on the AsyncContext so if container code also locks on that object deadlocks may occur.

How non-container thread defines current error state and gives response?

With the introduction of async processing and the possibility of non-container threads calling sendError() tracking the current error state and ensuring that the correct error page is called becomes more complicated. This state attribute helps by tracking the current error state and informing callers that attempt to change state if the change was successful or if another thread got there first.

   /** 
     * The state machine is very simple:
     *
     * 0 - NONE
     * 1 - NOT_REPORTED
     * 2 - REPORTED
     *
     *
     *   -->---->-- >NONE
     *   |   |        |
     *   |   |        | setError()
     *   ^   ^        |
     *   |   |       \|/
     *   |   |-<-NOT_REPORTED
     *   |            |
     *   ^            | report()
     *   |            |
     *   |           \|/
     *   |----<----REPORTED
     * 
     */

When executeNonBlockingDispatches(...) method is called in a non-container thread and how it interacts with SocketWrapper?

This method is called when non-blocking IO is initiated by defining a read and/or write listener in a non-container thread. It is called once the non-container thread completes so that the first calls to onWritePossible() and/or onDataAvailable() as appropriate are made by the container.

Processing the dispatches requires (for APR/native at least) that the socket has been added to the waitingRequests queue. This may not have occurred by the time that the non-container thread completes triggering the call to this method. Therefore, the coded syncs on the SocketWrapper as the container thread that initiated this non-container thread holds a lock on the SocketWrapper. The container thread will add the socket to the waitingRequests queue before releasing the lock on the socketWrapper. Therefore, by obtaining the lock on socketWrapper before processing the dispatches, we can be sure that the socket has been added to the waitingRequests queue.

Community
  • 1
  • 1
SkyWalker
  • 28,384
  • 14
  • 74
  • 132
  • 1
    This does not answer my question. You referred to a defect in some particular example application, which I didn't ask about. The message `An error occurred in processing while on a non-container thread` comes from Tomcat, not from any particular deployed application. I want to understand in which cases Tomcat decides to log that additional message when catching exception that was thrown out of an application. – TMG May 18 '16 at 21:36
  • @TMG I have got your concern. I have updated the answer. Please have a look and let me know. – SkyWalker May 19 '16 at 01:18
  • 2
    Seriously, does this answer really need to be this long? There is a whole lot of stuff in there that seems irrelevant to the Question asked. – Stephen C May 24 '16 at 11:59
  • 1
    @StephenC I agree with you, Sir. Actually solution portion is given in topmost. Then I have given skeleton details on updated section. – SkyWalker May 24 '16 at 12:42