Why do I get an UnmarshalOutOfBoundsException?

This exception typically occurs when a client and server are using incompatible Slice definitions, but it can also occur when the Ice run time fails to unmarshal a user exception.

On this page:

Mismatched Slice Definitions

Consider the following interface:

Slice
interface Example
{
    void op(int i , int j);
}

When a client invokes operation op, it supplies two integer parameters. The Ice run time marshals the parameters into the request that it sends on the wire. The request is preceded by a protocol header that, among other things, tells the server the total request size (including the 14-byte header). The server uses this information to read the appropriate number of bytes: it first reads the 14-byte header and checks the total request size. For example, that size might be 31 bytes. The server then reads the remainder of the request, namely, 31−14=17 bytes and places these 17 bytes into a buffer for subsequent unmarshaling. The buffer keeps track of how many bytes of the payload are available for reading and prevents attempts to read more data than was actually contained in the request.

The 17-byte payload of the request contains 8 bytes for the two integer parameters. (The remainder of the payload contains other details about the request, such as the object identity and request ID, among other things.) Once the server has identified the correct target operation, it dispatches the incoming request to the Slice-generated skeleton, which contains the code to unmarshal the two integer parameters. The skeleton retrieves 8 bytes from the unmarshaling buffer and converts them back into integers, and then passes these two integers to the implementation of operation op.

If the unmarshaling code in the skeleton tries to retrieve more data from the buffer than is actually available, the buffer raises an UnmarshalOutOfBoundsException. In plain language, the exception means "I expected a certain amount of data for the parameters of an invocation, but there wasn't as much data available as there should be." (Similar arguments apply when a client unmarshals the results of an invocation. In that case, the code goes through much the same actions, except that the unmarshaling is done by a proxy instead of a skeleton, and the data is contained in a reply instead of a request.)

So, how can this exception happen? Unless you are using the dynamic invocation or dispatch interfaces, the cause of this exception is usually a mismatch in the Slice definitions that are used by client and server. For example, suppose that, originally, the preceding interface looked as follows:

Slice
interface Example
{
    void op(int i); // Earlier version
}

During development, you decided to add the second parameter, to turn the interface into the two-integer version we saw earlier. Suppose you faithfully updated the server with the new version of the interface but, for some reason, you forgot to update the client. When you run client and server, the client runs with the old interface, but the server runs with the new interface. Of course, this means that the client will send only a single integer when it invokes op, but the server expects to receive two integers. This results in an UnmarshalOutOfBoundsException on the server side. (If we reverse the situation, such that the client expects two out-parameters, but the server sends only one, you would see the same exception on the client side instead.)

So, in short, UnmarshalOutOfBoundsException is often caused by mismatched Slice definitions, unless you are using the dynamic invocation or dispatch interfaces (in which case your code contains the mismatch).

Note that you can easily catch Slice mismatches at run time by adding the --checksum option when you compile your Slice definitions to generate Slice checksums. This option creates a dictionary in the generated code that contains a checksum for each Slice type. You can add an operation to the server that returns the dictionary to the client and verify in the client that the checksums for corresponding Slice types are the same; if they differ, you have mismatched Slice definitions.

Unknown User Exceptions

When a remote invocation throws a user exception, the Ice run time in the client will raise UnmarshalOutOfBoundsException if it does not recognize the exception. This situation can arise when the client and server are using incompatible Slice definitions, as discussed above. If your client receives UnmarshalOutOfBoundsException and you suspect it was thrown in the context of unmarshaling a user exception, you can confirm your suspicion by running the client with the Ice.Trace.Slicing property:

Ice.Trace.Slicing=1

With this property enabled, the Ice run time logs diagnostic messages whenever it fails to recognize an exception type.

In practice, the details of exception unmarshaling are a bit more complicated. Refer to the Ice protocol for more information.

Package Metadata vs. User Exceptions

In Java, you might be puzzled when the Ice run time raises an UnmarshalOutOfBoundsException while attempting to unmarshal a user exception. After all, you have already verified that the class for the user exception is available in your class path, so why is Ice unable to find it?

The most likely reason is the use of Slice metadata that altered the default packaging of your generated code, in which case the UnmarshalOutOfBoundsException indicates that the Ice run time was unable to locate the exception class in its new package. Consider the following example:

Slice
[["java:package:com.zeroc"]]
module Demo
{
    exception NoSuchRecord
    {
        string id;
    }
}

The slice2java compiler would normally map the Demo::NoSuchRecord exception to the Java class Demo.NoSuchRecord, but the presence of the metadata causes the compiler to generate com.zeroc.Demo.NoSuchRecord instead.

The problem arises when the Ice run time in a client attempts to unmarshal an instance of NoSuchRecord. The encoding for an exception includes a string representing the exception's Slice type ID, which in this case is ::Demo::NoSuchRecord. The Ice run time attempts to dynamically load the Java class that corresponds to this Slice type ID by translating the type ID into a Java class name. Ice uses the standard mapping rules by default, which produces a class name (Demo.NoSuchRecord) that does not exist. Consequently, Ice fails to unmarshal the exception and eventually raises UnmarshalOutOfBoundsException to the application.

The solution is to configure the Java run time so that it is able to successfully translate Slice type ids into Java class names. Two configuration properties are supported:

  • Ice.Package.module=package
    This property specifies the package prefix that the Ice run time should prepend to any mapped class name whose outermost Slice module is Module. In our example above, we can define a property like this:

    Ice.Package.Demo=com.zeroc
    
  • Ice.Default.Package=package
    This property specifies the name of a package to prepend to any mapped class name. Using our example again, we could define this property as follows:

    Ice.Default.Package=com.zeroc
    

Using one (or both) of these properties, you can supply the Ice run time with the information it needs to instantiate an exception.

See Also