InvalidStateError: Failed to execute 'transferControlToOffscreen' on 'HTMLCanvasElement': Cannot transfer control from a canvas more than once.
DotLottieWorkerReact on Next.js is throwing the following error:
InvalidStateError: Failed to execute 'transferControlToOffscreen' on 'HTMLCanvasElement': Cannot transfer control from a canvas more than once.
Hey @theashraf ! did you find anything useful?
We have the same issue. We use @lottiefiles/dotlottie-web@^0.34.0 with next@^14.2.13. (We preferred to use @lottiefiles/dotlottie-web over @lottiefiles/dotlottie-react due to an issue the react package has with config.layout)
Way to reproduce:
"use client";
import { DotLottieWorker, type Config } from "@lottiefiles/dotlottie-web";
import {
type ComponentPropsWithoutRef,
useEffect,
useLayoutEffect,
useRef,
} from "react";
type DotLottieAnimationProps = ComponentPropsWithoutRef<"canvas"> & {
readonly src: NonNullable<Config["src"]>;
readonly height: string;
readonly width: string;
};
const useIsomorphicLayoutEffect =
typeof window === "undefined" ? useEffect : useLayoutEffect;
function createLottieWorker(canvas: HTMLCanvasElement, src: string): DotLottieWorker {
return new DotLottieWorker({
workerId: "dotlottie-worker",
canvas,
backgroundColor: "transparent",
layout: { fit: "fit-width", align: [0.5, 0.5] },
renderConfig: {
autoResize: true,
freezeOnOffscreen: false,
devicePixelRatio: 5,
},
src,
loop: true,
autoplay: true,
});
}
export function DotLottieAnimation({
src,
height,
width,
style,
...props
}: DotLottieAnimationProps): React.ReactNode {
const ref = useRef<HTMLCanvasElement>(null);
useIsomorphicLayoutEffect(() => {
if (ref.current === null) {
return;
}
const worker = createLottieWorker(ref.current, src);
return () => {
void worker.destroy();
};
}, [ref, src]);
return <canvas ref={ref} style={{ height, width, ...style }} {...props} />;
}
We get the same error just by enabling StrictMode in our nextjs app.
@flow3d I haven't had time to look into this issue yet, but I'm happy to hear that you accept PRs if someone is interested in helping to fix it
Thanks to @lazybean comment I figured out it happens because createLottieWorker is called twice when StrictMode is enabled, causing a side-effect to run twice.
I made this patch to make sure the effect runs only once. This will prevent re-rendering on any state changes, so be aware that this solution might not be suitable for you.
export function DotLottieAnimation({
src,
height,
width,
style,
...props
}: DotLottieAnimationProps): React.ReactNode {
const ref = useRef<HTMLCanvasElement>(null);
useIsomorphicLayoutEffect(() => {
if (ref.current === null) {
return;
}
const { current: canvas } = ref;
// `createLottieWorker` has a side effect, so we have to force a single worker per canvas.
// This is a workaround to prevent multiple workers from being created, which could happen
// when react is on strict mode (development) or when the `src` prop changes.
// It means that changing the props `src` will not cause re-render.
if (canvas.hasAttribute("animation")) {
return;
}
canvas.setAttribute("animation", "true");
const worker = createLottieWorker(canvas, src);
return () => {
void worker.destroy();
};
}, [ref.current, src]);
return <canvas ref={ref} style={{ height, width, ...style }} {...props} />;
}
resolved in @lottiefiles/[email protected].
@theashraf I get the same exception and use recent version of next, react, @lottiefiles/dotlottie-react packages.
InvalidStateError: Failed to execute 'transferControlToOffscreen' on 'HTMLCanvasElement': Cannot transfer control from a canvas for more than one time. at c1.eval (webpack-internal:///(app-pages-browser)/./node_modules/@lottiefiles/dotlottie-react/dist/browser/index.js:14:381227) at Generator.next (
) at eval (webpack-internal:///(app-pages-browser)/./node_modules/@lottiefiles/dotlottie-react/dist/browser/index.js:9:833) at new Promise ( ) at g (webpack-internal:///(app-pages-browser)/./node_modules/@lottiefiles/dotlottie-react/dist/browser/index.js:9:649) at c1._create (webpack-internal:///(app-pages-browser)/./node_modules/@lottiefiles/dotlottie-react/dist/browser/index.js:14:381134) at new c1 (webpack-internal:///(app-pages-browser)/./node_modules/@lottiefiles/dotlottie-react/dist/browser/index.js:14:378396) at u0 (webpack-internal:///(app-pages-browser)/./node_modules/@lottiefiles/dotlottie-react/dist/browser/index.js:14:395347) at eval (webpack-internal:///(app-pages-browser)/./node_modules/@lottiefiles/dotlottie-react/dist/browser/index.js:14:392918) at commitAttachRef (webpack-internal:///(app-pages-browser)/./node_modules/next/dist/compiled/react-dom/cjs/react-dom-client.development.js:10780:44) at runWithFiberInDEV (webpack-internal:///(app-pages-browser)/./node_modules/next/dist/compiled/react-dom/cjs/react-dom-client.development.js:1511:30) at safelyAttachRef (webpack-internal:///(app-pages-browser)/./node_modules/next/dist/compiled/react-dom/cjs/react-dom-client.development.js:10798:9) at reappearLayoutEffects (webpack-internal:///(app-pages-browser)/./node_modules/next/dist/compiled/react-dom/cjs/react-dom-client.development.js:12311:11) at recursivelyTraverseReappearLayoutEffects (webpack-internal:///(app-pages-browser)/./node_modules/next/dist/compiled/react-dom/cjs/react-dom-client.development.js:12378:9) at reappearLayoutEffects (webpack-internal:///(app-pages-browser)/./node_modules/next/dist/compiled/react-dom/cjs/react-dom-client.development.js:12302:11) at recursivelyTraverseReappearLayoutEffects (webpack-internal:///(app-pages-browser)/./node_modules/next/dist/compiled/react-dom/cjs/react-dom-client.development.js:12378:9) at reappearLayoutEffects (webpack-internal:///(app-pages-browser)/./node_modules/next/dist/compiled/react-dom/cjs/react-dom-client.development.js:12258:11) at recursivelyTraverseReappearLayoutEffects (webpack-internal:///(app-pages-browser)/./node_modules/next/dist/compiled/react-dom/cjs/react-dom-client.development.js:12378:9) at reappearLayoutEffects (webpack-internal:///(app-pages-browser)/./node_modules/next/dist/compiled/react-dom/cjs/react-dom-client.development.js:12258:11) at recursivelyTraverseReappearLayoutEffects (webpack-internal:///(app-pages-browser)/./node_modules/next/dist/compiled/react-dom/cjs/react-dom-client.development.js:12378:9) at reappearLayoutEffects (webpack-internal:///(app-pages-browser)/./node_modules/next/dist/compiled/react-dom/cjs/react-dom-client.development.js:12302:11) at recursivelyTraverseReappearLayoutEffects (webpack-internal:///(app-pages-browser)/./node_modules/next/dist/compiled/react-dom/cjs/react-dom-client.development.js:12378:9) at reappearLayoutEffects (webpack-internal:///(app-pages-browser)/./node_modules/next/dist/compiled/react-dom/cjs/react-dom-client.development.js:12302:11) at recursivelyTraverseReappearLayoutEffects (webpack-internal:///(app-pages-browser)/./node_modules/next/dist/compiled/react-dom/cjs/react-dom-client.development.js:12378:9) at reappearLayoutEffects (webpack-internal:///(app-pages-browser)/./node_modules/next/dist/compiled/react-dom/cjs/react-dom-client.development.js:12302:11) at recursivelyTraverseReappearLayoutEffects (webpack-internal:///(app-pages-browser)/./node_modules/next/dist/compiled/react-dom/cjs/react-dom-client.development.js:12378:9) at reappearLayoutEffects (webpack-internal:///(app-pages-browser)/./node_modules/next/dist/compiled/react-dom/cjs/react-dom-client.development.js:12302:11) at recursivelyTraverseReappearLayoutEffects (webpack-internal:///(app-pages-browser)/./node_modules/next/dist/compiled/react-dom/cjs/react-dom-client.development.js:12378:9) at reappearLayoutEffects (webpack-internal:///(app-pages-browser)/./node_modules/next/dist/compiled/react-dom/cjs/react-dom-client.development.js:12258:11) at recursivelyTraverseReappearLayoutEffects (webpack-internal:///(app-pages-browser)/./node_modules/next/dist/compiled/react-dom/cjs/react-dom-client.development.js:12378:9) at reappearLayoutEffects (webpack-internal:///(app-pages-browser)/./node_modules/next/dist/compiled/react-dom/cjs/react-dom-client.development.js:12258:11) at doubleInvokeEffectsOnFiber (webpack-internal:///(app-pages-browser)/./node_modules/next/dist/compiled/react-dom/cjs/react-dom-client.development.js:16025:11) at runWithFiberInDEV (webpack-internal:///(app-pages-browser)/./node_modules/next/dist/compiled/react-dom/cjs/react-dom-client.development.js:1511:30) at recursivelyTraverseAndDoubleInvokeEffectsInDEV (webpack-internal:///(app-pages-browser)/./node_modules/next/dist/compiled/react-dom/cjs/react-dom-client.development.js:15987:17) at recursivelyTraverseAndDoubleInvokeEffectsInDEV (webpack-internal:///(app-pages-browser)/./node_modules/next/dist/compiled/react-dom/cjs/react-dom-client.development.js:15994:17) at recursivelyTraverseAndDoubleInvokeEffectsInDEV (webpack-internal:///(app-pages-browser)/./node_modules/next/dist/compiled/react-dom/cjs/react-dom-client.development.js:15994:17) at recursivelyTraverseAndDoubleInvokeEffectsInDEV (webpack-internal:///(app-pages-browser)/./node_modules/next/dist/compiled/react-dom/cjs/react-dom-client.development.js:15994:17) at recursivelyTraverseAndDoubleInvokeEffectsInDEV (webpack-internal:///(app-pages-browser)/./node_modules/next/dist/compiled/react-dom/cjs/react-dom-client.development.js:15994:17) at recursivelyTraverseAndDoubleInvokeEffectsInDEV (webpack-internal:///(app-pages-browser)/./node_modules/next/dist/compiled/react-dom/cjs/react-dom-client.development.js:15994:17) at recursivelyTraverseAndDoubleInvokeEffectsInDEV (webpack-internal:///(app-pages-browser)/./node_modules/next/dist/compiled/react-dom/cjs/react-dom-client.development.js:15994:17) at recursivelyTraverseAndDoubleInvokeEffectsInDEV (webpack-internal:///(app-pages-browser)/./node_modules/next/dist/compiled/react-dom/cjs/react-dom-client.development.js:15994:17) at recursivelyTraverseAndDoubleInvokeEffectsInDEV (webpack-internal:///(app-pages-browser)/./node_modules/next/dist/compiled/react-dom/cjs/react-dom-client.development.js:15994:17) at recursivelyTraverseAndDoubleInvokeEffectsInDEV (webpack-internal:///(app-pages-browser)/./node_modules/next/dist/compiled/react-dom/cjs/react-dom-client.development.js:15994:17) at recursivelyTraverseAndDoubleInvokeEffectsInDEV (webpack-internal:///(app-pages-browser)/./node_modules/next/dist/compiled/react-dom/cjs/react-dom-client.development.js:15994:17) at recursivelyTraverseAndDoubleInvokeEffectsInDEV (webpack-internal:///(app-pages-browser)/./node_modules/next/dist/compiled/react-dom/cjs/react-dom-client.development.js:15994:17) at recursivelyTraverseAndDoubleInvokeEffectsInDEV (webpack-internal:///(app-pages-browser)/./node_modules/next/dist/compiled/react-dom/cjs/react-dom-client.development.js:15994:17) at recursivelyTraverseAndDoubleInvokeEffectsInDEV (webpack-internal:///(app-pages-browser)/./node_modules/next/dist/compiled/react-dom/cjs/react-dom-client.development.js:15994:17) at recursivelyTraverseAndDoubleInvokeEffectsInDEV (webpack-internal:///(app-pages-browser)/./node_modules/next/dist/compiled/react-dom/cjs/react-dom-client.development.js:15994:17) at recursivelyTraverseAndDoubleInvokeEffectsInDEV (webpack-internal:///(app-pages-browser)/./node_modules/next/dist/compiled/react-dom/cjs/react-dom-client.development.js:15994:17) at recursivelyTraverseAndDoubleInvokeEffectsInDEV (webpack-internal:///(app-pages-browser)/./node_modules/next/dist/compiled/react-dom/cjs/react-dom-client.development.js:15994:17)
Hi @theashraf can I work on this...
sure @Sukuna0007Abhi