Skip to content

Commit 4caa423

Browse files
committed
fix: graceful error handling for GLM-OCR external data incompatibility
1 parent de85302 commit 4caa423

File tree

3 files changed

+126
-6
lines changed

3 files changed

+126
-6
lines changed

ai-worker-glm-ocr.js

Lines changed: 41 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,12 +55,23 @@ async function loadModel() {
5555
}
5656
}
5757

58-
// 2. Check WebGPU
58+
// 2. Check WebGPU — GLM-OCR requires WebGPU (q4f16 external data files
59+
// cannot be loaded by WASM's Module.MountedFiles)
5960
if (typeof navigator !== "undefined" && navigator.gpu) {
6061
const adapter = await navigator.gpu.requestAdapter();
6162
if (adapter) device = "webgpu";
6263
}
6364

65+
if (device !== "webgpu") {
66+
self.postMessage({
67+
type: "error",
68+
message: "GLM-OCR requires WebGPU which is not available in this browser. " +
69+
"Please use Chrome 113+, Edge 113+, or another WebGPU-capable browser. " +
70+
"Alternatively, use Granite Docling or Florence-2 which work without WebGPU.",
71+
});
72+
return;
73+
}
74+
6475
// Progress callback factory
6576
const progressCb = (label) => (progress) => {
6677
if (progress.status === "progress") {
@@ -108,16 +119,43 @@ async function loadModel() {
108119
});
109120
}
110121

111-
// 3. Load with fallback
122+
// 3. Load with fallback to onnx-community mirror
112123
try {
113124
await loadFromHost();
114125
} catch (primaryErr) {
126+
// Detect the known external-data incompatibility with onnxruntime-web 1.19.x
127+
const errMsg = primaryErr.message || "";
128+
if (errMsg.includes("MountedFiles") || errMsg.includes("external data file")) {
129+
self.postMessage({
130+
type: "error",
131+
message: "GLM-OCR is temporarily unavailable — the model's quantized weights require " +
132+
"a newer ONNX Runtime version that isn't yet compatible with this library. " +
133+
"Please use Granite Docling or Florence-2 for OCR in the meantime.",
134+
});
135+
return;
136+
}
137+
115138
console.warn(`textagent model failed: ${primaryErr.message}. Falling back to ${MODEL_ORG_FALLBACK}…`);
116139
self.postMessage({ type: "status", message: `Falling back to ${MODEL_ORG_FALLBACK} models…` });
117140
MODEL_ID = MODEL_ID.replace('textagent/', MODEL_ORG_FALLBACK + '/');
118141
processor = null;
119142
model = null;
120-
await loadFromHost();
143+
144+
try {
145+
await loadFromHost();
146+
} catch (fallbackErr) {
147+
const fbMsg = fallbackErr.message || "";
148+
if (fbMsg.includes("MountedFiles") || fbMsg.includes("external data file")) {
149+
self.postMessage({
150+
type: "error",
151+
message: "GLM-OCR is temporarily unavailable — the model's quantized weights require " +
152+
"a newer ONNX Runtime version that isn't yet compatible with this library. " +
153+
"Please use Granite Docling or Florence-2 for OCR in the meantime.",
154+
});
155+
return;
156+
}
157+
throw fallbackErr;
158+
}
121159
}
122160

123161
self.postMessage({ type: "loaded", device: device });
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
# GLM-OCR Graceful Error Handling
2+
3+
**Date:** 2026-03-23
4+
5+
## Summary
6+
7+
Added graceful error handling for the GLM-OCR model when it fails to load due to an
8+
incompatibility between `transformers.js@4.0.0-next.8` (the only version supporting the
9+
`glm_ocr` model type) and its bundled `onnxruntime-web@1.19.x` which cannot load external
10+
`.onnx_data` weight files in the browser.
11+
12+
## Problem
13+
14+
- GLM-OCR's quantized weights (`q4f16`) are stored in external `.onnx_data` files
15+
- ONNX Runtime Web requires explicit `externalData` session options to load these files
16+
in the browser (confirmed by official ONNX Runtime docs)
17+
- `transformers.js@4.0.0-next.8` does not pass `externalData` options to `InferenceSession.create()`
18+
- This caused a cryptic `Module.MountedFiles is not available` error on every page load
19+
20+
## Changes
21+
22+
### Modified Files
23+
- `ai-worker-glm-ocr.js` — Added WebGPU guard + `MountedFiles` / `external data file`
24+
error detection with a clear user-facing message
25+
- `public/ai-worker-glm-ocr.js` — Synced copy
26+
27+
### What Changed
28+
- **WebGPU guard:** If WebGPU is unavailable, the worker now returns a clear error
29+
suggesting Granite Docling or Florence-2 as alternatives
30+
- **External data error detection:** Catches the specific `MountedFiles` / `external data file`
31+
error pattern from ONNX Runtime and shows a user-friendly message:
32+
> "GLM-OCR is temporarily unavailable — the model's quantized weights require a newer
33+
> ONNX Runtime version that isn't yet compatible with this library."
34+
- **Prevents fallback retry:** The old code would fail on `textagent/GLM-OCR-ONNX`, then
35+
retry on `onnx-community/GLM-OCR-ONNX` with the same result. Now it detects the error
36+
immediately and stops
37+
- **Clears consent flag:** The error response triggers consent cleanup in `ai-assistant.js`,
38+
preventing stuck retry loops on page reload
39+
40+
## Resolution Path
41+
42+
The model will work automatically once `transformers.js` v4 stable releases with
43+
`onnxruntime-web ≥ 1.22` and adds `externalData` session option plumbing. At that point,
44+
only the `TRANSFORMERS_URL` version string needs updating.

public/ai-worker-glm-ocr.js

Lines changed: 41 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,12 +55,23 @@ async function loadModel() {
5555
}
5656
}
5757

58-
// 2. Check WebGPU
58+
// 2. Check WebGPU — GLM-OCR requires WebGPU (q4f16 external data files
59+
// cannot be loaded by WASM's Module.MountedFiles)
5960
if (typeof navigator !== "undefined" && navigator.gpu) {
6061
const adapter = await navigator.gpu.requestAdapter();
6162
if (adapter) device = "webgpu";
6263
}
6364

65+
if (device !== "webgpu") {
66+
self.postMessage({
67+
type: "error",
68+
message: "GLM-OCR requires WebGPU which is not available in this browser. " +
69+
"Please use Chrome 113+, Edge 113+, or another WebGPU-capable browser. " +
70+
"Alternatively, use Granite Docling or Florence-2 which work without WebGPU.",
71+
});
72+
return;
73+
}
74+
6475
// Progress callback factory
6576
const progressCb = (label) => (progress) => {
6677
if (progress.status === "progress") {
@@ -108,16 +119,43 @@ async function loadModel() {
108119
});
109120
}
110121

111-
// 3. Load with fallback
122+
// 3. Load with fallback to onnx-community mirror
112123
try {
113124
await loadFromHost();
114125
} catch (primaryErr) {
126+
// Detect the known external-data incompatibility with onnxruntime-web 1.19.x
127+
const errMsg = primaryErr.message || "";
128+
if (errMsg.includes("MountedFiles") || errMsg.includes("external data file")) {
129+
self.postMessage({
130+
type: "error",
131+
message: "GLM-OCR is temporarily unavailable — the model's quantized weights require " +
132+
"a newer ONNX Runtime version that isn't yet compatible with this library. " +
133+
"Please use Granite Docling or Florence-2 for OCR in the meantime.",
134+
});
135+
return;
136+
}
137+
115138
console.warn(`textagent model failed: ${primaryErr.message}. Falling back to ${MODEL_ORG_FALLBACK}…`);
116139
self.postMessage({ type: "status", message: `Falling back to ${MODEL_ORG_FALLBACK} models…` });
117140
MODEL_ID = MODEL_ID.replace('textagent/', MODEL_ORG_FALLBACK + '/');
118141
processor = null;
119142
model = null;
120-
await loadFromHost();
143+
144+
try {
145+
await loadFromHost();
146+
} catch (fallbackErr) {
147+
const fbMsg = fallbackErr.message || "";
148+
if (fbMsg.includes("MountedFiles") || fbMsg.includes("external data file")) {
149+
self.postMessage({
150+
type: "error",
151+
message: "GLM-OCR is temporarily unavailable — the model's quantized weights require " +
152+
"a newer ONNX Runtime version that isn't yet compatible with this library. " +
153+
"Please use Granite Docling or Florence-2 for OCR in the meantime.",
154+
});
155+
return;
156+
}
157+
throw fallbackErr;
158+
}
121159
}
122160

123161
self.postMessage({ type: "loaded", device: device });

0 commit comments

Comments
 (0)