-
Notifications
You must be signed in to change notification settings - Fork 3.4k
Description
Describe the bug
Images are not rendering in the labeling interface. Network requests for image data succeed (200 OK), but the <img> element is not generated. The browser console shows
mobx-state-tree error when the setError method attempts to modify state outside of an action context.
Console error:
Uncaught (in promise) Error: [mobx-state-tree] Cannot modify 'ImageEntity@/annotationStore/annotations/0/root/children/0/imageEntities/0(id: image#0@C17cO)', the object i protected and can only be modified by using an action.
at ImageEntity.js:238:20
To Reproduce
- Go to a project with images stored in AWS S3
- Click on a task to open the labeling interface
- Observe that the image area is blank
- Open browser DevTools → Console tab
- See the mobx-state-tree error
Expected behavior
The image should be displayed in the labeling interface. If image loading fails, an error message should be shown without breaking the entire rendering process.
The .lsf-image container only contains a 1px canvas overlay, with no <img> element:
<div class="lsf-image" style="width: 100%; height: auto;">
<canvas class="overlay--kj18y" style="width: 1px; height: 1px; ..."></canvas>
</div>Environment (please complete the following information):
- OS: N/A (HumanSignal Cloud)
- Label Studio Version: HumanSignal Cloud (app.heartex.com) - latest as of 2026-02-03
- Storage: AWS S3
Additional context
Root Cause Identified
cc @bmartel
The bug was introduced in #6930 (merged 2025-01-27).
In ImageEntity.js, the img.onerror callback modifies mobx-state-tree state outside of an action context:
img.onerror = () => {
self.setError(true); // ← This might be outside action context
self.setDownloading(false);
resolve();
};Since onerror is an asynchronous callback, it may execute outside the original preload() action's context. In mobx-state-tree, modifying state outside of an action throws an exception, which could be interrupting the image rendering process.
Possible Fix (suggested by Claude)
Claude suggested that wrapping the state modifications in runInAction might resolve the issue:
import { runInAction } from "mobx";
img.onerror = () => {
runInAction(() => {
self.setError(true);
self.setDownloading(false);
});
resolve();
};I'm not entirely sure if this is the correct approach, so please let me know if there's a better solution.
