{"record":{"id":"d609d0f939c56ce1","repo":"remotion-dev/remotion","slug":"a-skill-is-already-being-installed-or-removed-please-try","errorCode":null,"errorMessage":"A skill is already being installed or removed. Please try again once it finishes.","messagePattern":"A skill is already being installed or removed\\. Please try again once it finishes\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/studio-server/src/preview-server/routes/install-remotion-skill.ts","lineNumber":31,"sourceCode":"\nconst changingSkillsInProjects = new Set<string>();\n\nconst changeRemotionSkill = async ({\n\taction,\n\tremotionRoot,\n\tinput: {skill},\n\tlogLevel,\n}: Parameters<\n\tApiHandler<InstallRemotionSkillRequest, GetRemotionSkillsInfoResponse>\n>[0] & {\n\treadonly action: 'install' | 'remove';\n}): Promise<GetRemotionSkillsInfoResponse> => {\n\tif (!remotionSkillNames.some((name) => name === skill)) {\n\t\tthrow new Error(`Unknown Remotion skill: ${JSON.stringify(skill)}`);\n\t}\n\n\tif (changingSkillsInProjects.has(remotionRoot)) {\n\t\tthrow new Error(\n\t\t\t'A skill is already being installed or removed. Please try again once it finishes.',\n\t\t);\n\t}\n\n\tchangingSkillsInProjects.add(remotionRoot);\n\ttry {\n\t\tconst installedSkill = getRemotionSkillsInfo({remotionRoot}).skills.find(\n\t\t\t({name}) => name === skill,\n\t\t);\n\t\tconst removingGlobally =\n\t\t\taction === 'remove' &&\n\t\t\tinstalledSkill?.installedInProject === false &&\n\t\t\tinstalledSkill.installedGlobally;\n\t\tif (\n\t\t\taction === 'remove' &&\n\t\t\t!removingGlobally &&\n\t\t\t!installedSkill?.installedInProject\n\t\t) {","sourceCodeStart":13,"sourceCodeEnd":49,"githubUrl":"https://github.com/remotion-dev/remotion/blob/46a3a6bf13ca367376ff18bbb06dae2e87e0d068/packages/studio-server/src/preview-server/routes/install-remotion-skill.ts#L13-L49","documentation":"changeRemotionSkill serializes skill install/remove operations per Remotion project using a `changingSkillsInProjects` set. If a skill change is already in flight for the same remotionRoot, a second concurrent request is rejected with this error so two package-manager operations never interleave on one project. The message tells the caller to wait and retry.","triggerScenarios":"Calling installRemotionSkillHandler or removeRemotionSkillHandler for a remotionRoot while a previous install/remove for the same root is still running (the set contains the root).","commonSituations":"Double-clicking the install button in Studio; two browser tabs triggering installs for the same project; an automation script firing requests without awaiting the previous one.","solutions":["Wait for the in-progress install/remove to finish (watch the Studio UI progress indicator), then retry","Debounce or serialize requests in client code so only one skill change runs at a time per project","Reload the Studio page if the previous operation is believed to have crashed and left the lock stuck"],"exampleFix":"// before: parallel requests\nawait Promise.all([installSkill('a'), installSkill('b')])\n// after: sequential\nawait installSkill('a');\nawait installSkill('b');","handlingStrategy":"retry","validationCode":"// track in-flight operations client-side\nlet inFlight = false;\nif (inFlight) throw new Error('A skill change is already running');","typeGuard":null,"tryCatchPattern":"try {\n  await installSkill(skill);\n} catch (e) {\n  if (e.message.includes('already being installed or removed')) {\n    await waitForCurrentOperation();\n    await installSkill(skill); // retry once\n  }\n}","preventionTips":["Serialize skill operations: await each before starting the next","Disable install/remove buttons while an operation is in flight","Use a single Studio tab per project for skill management"],"tags":["concurrency","lock","studio"],"backgroundTag":"invalid-state-transition","analyzedSha":"46a3a6bf13ca367376ff18bbb06dae2e87e0d068","analyzedAt":"2026-09-18T00:12:20.256Z","contentChangedAt":"2026-09-18T00:12:20.256Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}