Recommended Free Tools
iTechGuides is reader-supported. When you buy through links on our site, we may earn an affiliate commission. As an Amazon Associate I earn from qualifying purchases. Learn more
The most common reason a Fabric.js editor looks half-restored after loadFromJSON is that the code treats the call as synchronous. In the current StaticCanvas API, loadFromJSON returns a Promise, so anything that runs right after the call can execute before the objects, background and overlay are in place. Waiting for the Promise fixes that timing problem, but it does not guarantee that every serialized object was rebuilt. A single object can fail inside the reviver while the rest of the document loads normally, and an overlapping second load or data saved by a different Fabric.js version can produce the same visible symptom.
What “half-loaded” usually looks like
In practice the symptom takes one of a few forms: the canvas is blank when your “ready” logic runs, some shapes or images are missing, objects appear but in the wrong place or with the wrong size, or the document looks correct until the user edits something. Each form points to a different cause, so it helps to identify which one you are seeing before changing code.
Cause 1: Treating loadFromJSON as synchronous
The method is asynchronous. The current StaticCanvas documentation at the Fabric.js StaticCanvas API page describes it as returning a Promise that resolves to the canvas. Code that calls the method and then immediately sets a “document ready” flag, reads object counts, or runs export logic is reading state from before the load has finished.
Do these 3 things before closing this tab:
1Fix the driver behind crashes, sound loss and screen glitches2Repair Windows errors before they cause bigger problems3Scan for outdated or missing drivers - takes under a minuteThe fix is to put every post-load step inside the completion path. The official example calls requestRenderAll() after the Promise resolves:
#1 Best Overall
const data = JSON.parse(savedText);
await canvas.loadFromJSON(data);
canvas.requestRenderAll();
setDocumentReady(true);
If your loader is a plain function rather than an async function, use .then() and keep the same ordering. Any error thrown by JSON.parse happens before the call, so wrap that step separately so a malformed file is reported rather than leaving the editor in an intermediate state.
Cause 2: Individual objects failing inside the reviver
A resolved Promise tells you the load procedure completed; it does not tell you that each object was recreated. The API lets you pass a reviver that runs after each object is created, and that reviver receives an optional error argument for objects whose creation failed. Your reviver may return a replacement FabricObject in place of the failed one.
This matters because the default outcome is silent. If you do not log the error argument, a missing shape looks the same as a shape that was never saved. Record the serialized type and the error for every object during diagnosis. Then choose a policy deliberately:
Rank #2
- Substitute a placeholder when the user must still see that an object exists, for example a labeled rectangle where an image failed to load.
- Omit the object when the failure is not user-visible and a partial document is acceptable, but log it so the omission is traceable.
- Reject the whole load when a missing object would make the document misleading or unsafe to edit.
Common triggers in application code are image sources that no longer resolve and custom object types that the current build does not register. The evidence available for this article establishes that per-object errors exist and are reported through the reviver; it does not establish which resource failure applies to any particular application, so confirm that from your own logs.
Cause 3: Overlapping loads
If a user switches documents, or an autosave restore starts while an earlier restore is still running, two loads can write into the same canvas. The result is often a mix of objects from both documents or a canvas that stops reflecting the most recent request. The current API documentation states the remedy directly: it recommends aborting loading tasks before calling loadFromJSON to prevent race conditions and unnecessary networking.
Abort any earlier loading task your code started, then also guard the completion path so a stale load cannot mark its document as active:
let activeLoad = 0;
async function openDocument(canvas, data) {
const loadId = ++activeLoad;
await canvas.loadFromJSON(data);
if (loadId !== activeLoad) return; // a newer load has started
canvas.requestRenderAll();
setDocumentReady(true);
}
The counter is an application-level guard, not part of Fabric.js. It keeps your document identity tied to the load that actually finished last.
Cause 4: Data created by a different Fabric.js version
Serialized JSON is tied to the format of the version that wrote it. The Fabric.js v5 migration guide, at the v5 breaking-changes page, documents a change in how circle startAngle and endAngle are interpreted, moving from radians to degrees. Circles saved before that change can therefore load without an error and still draw as arcs in the wrong place. The guide includes a reviver example that converts legacy circle data.
Two points limit how far you should take this. The conversion targets legacy circle data, so applying it to every object in every document will corrupt documents that were already correct. And the guide describes a change in one version boundary; it is not a general statement about all format differences. Identify the version that produced each saved document, and apply migration logic only to documents from that version.
Rank #4
Background and overlay setup in legacy v5 code
The Fabric.js v5 source documentation, at the v5 source reference, describes a loading sequence from the callback era in which restoring objects was coordinated with setting up background and overlay content. Treat that as v5-era implementation detail rather than current behavior. Its practical value is explanatory: if your application shows the objects but not the background or overlay, a readiness signal that fires before the background and overlay are set can make the editor look partly loaded. Check that the background and overlay you render are included in the same completion path as the objects.
For the image-related history behind some of these failures, the older Fabric.js v1 changelog documents early image error and pattern-loading handling. It is useful background for why image failures can be easy to miss, but it does not describe current behavior.
Diagnostic sequence
- Record the installed Fabric.js version and the version of the application that saved each document.
- Parse and validate the input before passing it to Fabric.js. Confirm that it has the structure produced by
toJSONfor the installed version. - Await
canvas.loadFromJSON(data), then move the “document ready” update and the finalrequestRenderAll()into the completion path. - Add a reviver that logs each object’s type and any error argument. Decide whether failed objects are replaced, omitted or cause the load to be rejected.
- When the logs show failures, check image sources, background and overlay requests, and any custom object types in that order.
- Abort any earlier loading task before starting a new one, and ignore the completion of a load that has been superseded.
- For older documents, test the legacy circle conversion on a copy first, and apply it only to documents saved by the affected version.
Matching symptoms to likely causes
The table below is a troubleshooting heuristic drawn from the causes above. It is not a guaranteed rule of Fabric.js behavior, and a real application can show more than one pattern at once.
Best Value
| Symptom | Check first | Likely cause |
|---|---|---|
| Canvas is blank when the editor reports ready | Whether post-load code runs before the Promise resolves | Synchronous assumption (Cause 1) |
| Some objects are missing, the rest are correct | Reviver error argument for each missing object | Per-object creation failure (Cause 2) |
| Objects from two documents appear together | Whether two load calls overlapped | Overlapping loads (Cause 3) |
| Old circles are in the wrong place or wrong size | Save date and Fabric.js version of the document | Version change in circle angles (Cause 4) |
| Objects are correct but background or overlay is absent | Whether background and overlay are set in the completion path | Readiness signal fired too early (legacy v5 pattern) |
What can and cannot be determined from outside your project
The exact cause of a half-loaded editor depends on the installed version, the saved JSON, the reviver’s error output, network activity for images, and the order in which your code starts loads. Without those details, no general article can name the single cause in your editor. The steps above are designed so that the logs you collect will identify it.
The Fabric.js documentation consulted here describes the current Promise-based API and the abort recommendation. The v5 material describes an older implementation and should be read as history. This article does not identify a current package release that fixes these issues, so check the release notes for your installed version before assuming a particular fix is included.
Once the reviver logs and version checks are in place, the rest of the diagnosis is usually straightforward: the timing problem is fixed by awaiting, the silent object loss is fixed by logging and choosing a policy, and the wrong-data problem is fixed by migrating only the documents that need it.
For related reading on the topic, the StaticCanvas API reference remains the primary source for the method’s signature and reviver contract, and the enlivenObjects utility page documents the Promise-based helper that rebuilds serialized objects.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

