APL Reshape (⍴) Errors: Diagnosing DOMAIN, RANK and Silent Cycling
APL's ⍴ does not raise a shape-mismatch error — it cycles. Here is how to tell cycling from a bad shape operand, and which checks to run first.
12 Nov 2025, 07:21 UTC

Two different complaints land on the same primitive. One group gets a hard error from ⍴ — usually DOMAIN ERROR or RANK ERROR. The other gets no error at all and a result full of values they did not expect. Both are reshape problems, but they have almost nothing in common, and the fix for one makes the other worse.
Dyadic reshape is shape ⍴ array: the left argument is the shape you want, the right argument supplies the elements. The elements are taken from the ravel of the right argument — its elements in row-major order — and restart from the beginning when they run out. That last clause is the source of most confusion.
The condition: you expected a mismatch error and got something else
In mainstream APLs (Dyalog, APL2, GNU APL), 2 3 ⍴ ⍳4 is legal. It does not raise a shape-mismatch error; it produces a 2×3 result whose ravel is 1 2 3 4 1 2. Reshape cycles. If your mental model came from a language where reshaping requires an exact element count, every silent wrong answer you are seeing is explained by this one rule.
The exception is an empty right argument. 2 3 ⍴ ⍬ also produces no error, but there are no elements to cycle, so the result is filled with the prototype of the right argument — the fill element APL uses for that type (numeric zero for a numeric empty, space for a character empty). That is the one place where reshape can quietly hand you data that looks plausible and is entirely synthetic.
Cause and diagnostic table
Error names below follow Dyalog and APL2 conventions. The conditions are portable; the names and error numbers are not.
| Symptom | Underlying cause | First check |
|---|---|---|
DOMAIN ERROR | Shape contains a negative, fractional, or non-numeric value | shape, then shape ≡ ⌊shape and shape ≥ 0 |
RANK ERROR | Left argument is not a vector (a matrix or higher-rank array) | ⍴⍴shape — must be 0 or 1 |
LIMIT ERROR | Requested rank or a single dimension exceeds the interpreter's cap | ⍴⍴shape and ×/shape |
WS FULL | Result cannot fit in the workspace | ×/shape against ⎕WA |
| No error, wrong values | Cycling, or prototype fill from an empty right argument | ×/shape vs ≢,array, and 0 = ≢,array |
| No error, unexpected type | Prototype fill, not coercion — reshape never converts element types | ⎕DR result vs ⎕DR array |
Ordered checks
- Confirm you are reshaping at all. Monadic
⍴xis shape-of and returns a shape vector. Only a left argument makes it reshape. A missing or misplaced left argument changes the meaning of the line without any error. - Inspect the shape in isolation. Assign it to a name and evaluate
⍴⍴shape(rank),shape(the values), and⎕DR shapecompared with⎕DR 0(numeric or not). - Compare element counts.
×/shapeis the number of elements requested; note that×/⍬is 1, which is why an empty shape vector yields a scalar.≢,arrayis the number of elements available. If they differ, you are relying on cycling. - Check for an empty right argument.
0 = ≢,arraymeans every element in the result is a fill, regardless of the shape. - Check the result, not just the input.
⍴resultconfirms the shape;⎕DR resultconfirms the type. If the type differs from the source, look for an empty right argument rather than a coercion bug.
Fixes matched to findings
- Negative or fractional value in the shape: fix the arithmetic that produced it. Do not assume signed reshape semantics; Dyalog, APL2, and GNU APL all reject negative dimensions. If truncation is intended, apply
⌊deliberately and document it. - Non-numeric shape: you probably built the shape from parsed text. Convert before reshaping. Dyalog's
⎕VFIverifies and fixes numeric input and returns a validity flag alongside the values, which lets you reject bad input instead of reshaping with it. - Matrix left argument: ravel it with
(,shape)⍴array— but only if flattening the shape is what you meant. A matrix shape is usually a sign that an earlier operation returned the wrong rank. - Unwanted cycling: if you want an error instead of silent repetition, add a guard. In Dyalog,
⎕SIGNAL 5raises aLENGTH ERROR(error numbers are Dyalog-specific):
This converts the silent case into a loud one at the call site, which is usually what a diagnostic-minded codebase wants.Reshape ← { (×/⍺) ≢ ≢,⍵ : ⎕SIGNAL 5 ⋄ ⍺⍴⍵ } - Prototype fill from an empty argument: decide explicitly what an empty input should produce. Either supply a fill value before reshaping (
⍺ ⍴ ⍵ , 0for numeric work) or guard with0 = ≢,⍵and return a documented empty result. LIMIT ERRORorWS FULL: reduce the shape, or build the result in slices and catenate. Neither error is about your data; both are about the size of the request.
A concrete comparison: cycling versus fill
shape ← 2 3
data ← ⍳4
shape ⍴ data
Documented behaviour: a 2×3 matrix whose ravel is 1 2 3 4 1 2. The final two elements repeat because the source ran out. No error is raised.
2 3 ⍴ ⍬
Documented behaviour in Dyalog: a 2×3 matrix of zeros, because the prototype of a numeric empty vector is 0. Substitute '' for ⍬ and you get spaces instead. Both results are structurally valid and semantically empty — the kind of value that propagates through a pipeline without complaint. Verify both in your own interpreter before relying on the fill element.
Verifying the result
Work in a scratch namespace so a failed reshape cannot corrupt state. After the operation, check three things: ⍴result matches the shape you asked for, ≢,result equals ×/shape, and result matches the corresponding slice of the source ravel. For the last check, compare against (×/shape) ↑ (,array) , (,array) rather than eyeballing the display.
When an error does occur, Dyalog 16.0 and later exposes the diagnostic message object ⎕DMX, whose Message and DM fields carry the full text and the error number. That is more reliable to log than a screenshot of the session.
When to escalate
- The identical expression succeeds in one interpreter and fails in another. That is an implementation difference, not a bug in your code. Record both interpreters and versions.
LIMIT ERRORappears at a rank you believe is within the documented cap. Check the cap for your specific version; rank limits are not uniform across APLs.WS FULLpersists after the shape has been reduced to a size you have successfully allocated before. That points at workspace or memory configuration, not at reshape.
A useful escalation report contains: the exact expression, the shape vector as a literal, ⎕DR of both arguments, the interpreter name and version, and the complete error text from ⎕DMX rather than a paraphrase.
Limitations and a note for review
Error names, error numbers, rank caps, and fill rules vary by implementation and version. ⎕DMX, ⎕VFI, and ⎕SIGNAL are Dyalog facilities; other APLs provide different or no equivalents. The planning brief behind this article listed shape-mismatch and type coercion as reshape errors — in mainstream APLs reshape cycles rather than erroring on a count mismatch, and it rearranges existing elements without converting their types. Treat those two items as unconfirmed and check them against your interpreter's own documentation before acting on them.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.