PaddlePaddle/PaddleOCR · error
Unexpected rec output dims: [${dims.join(", ")}]
Error message
Unexpected rec output dims: [${dims.join(", ")}] What it means
Thrown by rec postprocess() when the recognition model's output tensor is not rank 3. CTC decoding requires the layout [N, T, C] (batch, timesteps, classes); any other rank (e.g. 2D [T*C] or 4D) cannot be decoded and the code aborts. This is the recognition-side analogue of the det dims guards and indicates a wrong or differently-exported ONNX model.
Source
Thrown at paddleocr-js/packages/core/src/models/rec.ts:294
}
}
if (maxIdx > 0 && maxIdx !== prevIdx) {
const dictIdx = maxIdx - 1;
if (dictIdx >= 0 && dictIdx < charDict.length) {
text += charDict[dictIdx];
probs.push(maxVal);
}
}
prevIdx = maxIdx;
}
const score = probs.length ? probs.reduce((a, b) => a + b, 0) / probs.length : 0;
return { text, score };
}
function postprocess(output: Tensor, charDict: string[]): Array<{ text: string; score: number }> {
const dims = output.dims;
if (dims.length !== 3) {
throw new Error(`Unexpected rec output dims: [${dims.join(", ")}]`);
}
const sampleCount = dims[0];
const timeSteps = dims[1];
const classes = dims[2];
const data = output.data as Float32Array;
const stride = timeSteps * classes;
const results: Array<{ text: string; score: number }> = [];
for (let index = 0; index < sampleCount; index += 1) {
results.push(decodeCTCSample(data, index * stride, timeSteps, classes, charDict));
}
return results;
}
View on GitHub (pinned to 2661c7c0ef)
Solutions
- Log the dims included in the message and compare to the expected [batch, timesteps, classes]
- Use the rec model file bundled with / referenced by this paddleocr-js version
- If re-exporting, keep the softmax logits output as rank 3 and do not fold decode ops into the graph
- Verify the config's model asset descriptor points at a CRNN/SVTR-style CTC recognition model
Defensive patterns
Strategy: try-catch
Type guard
function isCtcLogitsDims(dims: readonly number[]): dims is [number, number, number] {
return dims.length === 3;
} Try / catch
try { await recModel.predict(cv, crops); } catch (e) {
if (e instanceof Error && /Unexpected rec output dims/.test(e.message)) {
// wrong rec model or folded decode ops in the graph: use the bundled CTC rec asset
} else throw e;
} Prevention
- Only load CRNN/SVTR-style CTC recognition models whose logits output is rank 3 [N,T,C]
- Keep decode ops (argmax/CTC) out of the exported graph; decode in JS
- Smoke-test one crop after swapping rec model files
When it happens
Trigger: Loading a non-CTC rec model or a classifier into the rec slot; a re-exported model whose logits were reshaped/squeezed at the graph tail; an ONNX Runtime version altering output rank for dynamic shapes.
Common situations: Mixing model versions (rec ONNX from one release with core code from another); custom export adding argmax/greedy-decode nodes into the graph so the raw logits never reach the JS side; wrong model wired via config asset descriptors.
Related errors
- Unexpected det output dims: [${dims.join(", ")}]
- Unexpected det output dims: [${od.join(", ")}]
- Detection batch output N=${String(nOut)} does not match inpu
- Recognition model session is not initialized.
- Unexpected recognition channels: ${String(channels)}
AI-assisted analysis of PaddlePaddle/PaddleOCR@2661c7c0ef (2026-08-14).
Data as JSON: /api/errors/59c268edeb33eb85.
Report an issue: GitHub.