ReactiveX/rxjs · error · Error
Refusing to install over a ${state} Skill copy at ${installa
Error message
Refusing to install over a ${state} Skill copy at ${installation.targetPath}. Use update or explicit force. What it means
Thrown by installSkill when the target skill path already contains a copy whose state is not 'absent' (stale or locally modified) and --force was not passed. It prevents silently clobbering a user's local edits on install; the message tells you to use update instead or force explicitly.
Source
Thrown at packages/migrate/src/skill-install.ts:121
export async function inspectSkillInstallation(options: SkillInstallOptions): Promise<SkillInstallationInspection> {
const installation = await resolveInstallation(options);
const state = await installationState(installation);
const provenance = state === 'absent' ? undefined : await tryReadProvenance(installation.provenancePath);
return {
state,
targetPath: installation.targetPath,
provenancePath: installation.provenancePath,
...(provenance ? { provenance } : {}),
canonicalIntegrity: installation.provenance,
};
}
export async function installSkill(options: SkillInstallOptions): Promise<SkillInstallResult> {
const installation = await resolveInstallation(options);
const state = await installationState(installation);
if (state === 'current') return resultFor('install', installation, state, state, false);
if (state !== 'absent' && !options.force) {
throw new Error(`Refusing to install over a ${state} Skill copy at ${installation.targetPath}. Use update or explicit force.`);
}
await replaceInstallation(installation);
return resultFor('install', installation, state, 'current', true);
}
export async function updateSkill(options: SkillInstallOptions): Promise<SkillInstallResult> {
const installation = await resolveInstallation(options);
const state = await installationState(installation);
if (state === 'current') return resultFor('update', installation, state, state, false);
if (state === 'modified' && !options.force) {
throw new Error(`Refusing to overwrite a locally modified Skill copy at ${installation.targetPath} without explicit force.`);
}
await replaceInstallation(installation);
return resultFor('update', installation, state, 'current', true);
}
export async function removeSkill(options: SkillInstallOptions): Promise<SkillInstallResult> {
const installation = await resolveInstallation(options);View on GitHub (pinned to 54796b38a5)
Solutions
- Run rxjs-migrate-skill update instead, which is the intended path for existing copies
- If local changes are disposable, rerun install with --force
- Diff the installed copy against the canonical one to see what would be overwritten
Example fix
# before rxjs-migrate-skill install --harness claude # after rxjs-migrate-skill update --harness claude # or, discarding local edits: rxjs-migrate-skill install --harness claude --force
Defensive patterns
Strategy: try-catch
Validate before calling
import { stat } from 'node:fs/promises';
const exists = await stat(targetSkillPath).then(() => true).catch(() => false); Try / catch
try { installSkill(opts); } catch (e) { if (e instanceof Error && e.message.startsWith('Refusing to install')) { await updateSkill(opts); } else throw e; } Prevention
- Prefer 'update' for existing installs
- Only use --force when local edits are disposable
When it happens
Trigger: Running rxjs-migrate-skill install when a previous skill copy exists that doesn't match the canonical digest (edited by hand or from an older version), without --force.
Common situations: Re-running install after manually tweaking SKILL.md, or after upgrading @rxjs/migrate changed the canonical skill content.
Related errors
- Refusing to overwrite a locally modified Skill copy at ${ins
- Refusing to remove a locally modified Skill copy at ${instal
- Invalid Skill installation provenance.
- Unknown mode: ${mode}
- Unknown framework: ${framework}
AI-assisted analysis of ReactiveX/rxjs@54796b38a5 (2026-08-28).
Data as JSON: /api/errors/29a935fbf98d9790.
Report an issue: GitHub.