fix: raise clear error for on-disk (splayed) table reference - #104
Merged
Conversation
Reading a splayed/partitioned table (e.g. `get `:test/ set ([] a:til 10)`) crashed the client with an opaque "ClassCastException: class java.lang.String cannot be cast to class [Ljava.lang.Object;". kdb+ transmits such a table as table(98) -> dict(99) whose value is the on-disk path symbol (`:test/`, type -11) rather than the column data, so the Flip(Dict) constructor's (Object[]) dict.y cast fails. The column data is not present in the message and cannot be materialized on the Java side. Detect this case in Flip(Dict) and throw a descriptive IllegalArgumentException that names the referenced path and explains how to materialize the table in kdb+ before sending it. Add a unit test built from the exact IPC bytes reported in issue KxSystems#51.
sshanks-kx
reviewed
Jul 31, 2026
| public Flip(Dict dict){ | ||
| x=(String[])dict.x; | ||
| if(!(dict.y instanceof Object[])) | ||
| throw new IllegalArgumentException("Cannot create a Flip from a table whose column data is stored on disk" |
Collaborator
There was a problem hiding this comment.
Although useful in this situation, equally someone could have a bug in their code which could trigger this error (e.g bug in how they constructed a Dict). In which case the explanation in the exception would be confusing and misleading for them.
Contributor
Author
There was a problem hiding this comment.
Good point, thanks — reworded so the message leads with the actual condition (the dictionary values must be an Object[] of columns) and presents both a splayed/on-disk table and a mis-constructed Dict as possible causes, rather than assuming the on-disk case. Also added a test for the plain mis-constructed-Dict path. Pushed in fadbed5.
Address review feedback on PR KxSystems#104: the guard fires whenever the dict values are not an Object[] of columns, which can also result from a mis-constructed Dict, not only a splayed/on-disk table. Reword the message to lead with the actual condition and present both causes, so it does not mislead a caller whose own code produced the bad Dict. Add a test for the mis-constructed-Dict case.
sshanks-kx
approved these changes
Jul 31, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Deserializing an on-disk (splayed/partitioned) table reference crashes the client with an opaque
ClassCastExceptioninstead of a meaningful error. This PR turns that into a clear, actionable exception.Addresses #51.
Reproduction
Root cause
A splayed table whose columns live on disk is transmitted as
table(98) → dict(99)whose value is the on-disk path symbol (`:test/, type-11) rather than the column data.Flip(Dict)unconditionally castsdict.ytoObject[], which fails for the symbol atom. The column data is simply not present in the message, so it cannot be reconstructed on the Java side (q itself errors with'test/a. OS reports: No such file or directorywhen you index such a table without disk access).Change
Flip(Dict)now detects when the value is not a list of columns and throws a descriptiveIllegalArgumentExceptionnaming the referenced path and explaining how to materialize the table in kdb+ before sending it, e.g.:This is a minimal, non-breaking change (the previous behaviour was already an unchecked exception, just an opaque one) and leaves normal in-memory tables untouched.
Testing
testDeserializeSplayedTableReference, built from the exact IPC bytes captured in ClassCastException on reading splay table #51, asserting the clearIllegalArgumentException.