ReactiveX/rxjs · error · Error

Refusing to overwrite a locally modified Skill copy at ${ins

Error message

Refusing to overwrite a locally modified Skill copy at ${installation.targetPath} without explicit force.

What it means

Thrown by updateSkill when the existing skill copy is state 'modified' (its digest no longer matches canonical) and --force is absent. The update would destroy local edits, so the CLI requires explicit consent.

Source

Thrown at packages/migrate/src/skill-install.ts:132

}

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);
  const state = await installationState(installation);
  if (state === 'absent') return resultFor('remove', installation, state, state, false);
  if (state === 'modified' && !options.force) {
    throw new Error(`Refusing to remove a locally modified Skill copy at ${installation.targetPath} without explicit force.`);
  }
  await rm(installation.targetPath, { recursive: true, force: false });
  return resultFor('remove', installation, state, 'absent', true);
}

export function manageSkillInstallation(action: SkillInstallAction, options: SkillInstallOptions): Promise<SkillInstallResult> {
  switch (action) {

View on GitHub (pinned to 54796b38a5)

Solutions

  1. Back up your local edits, rerun with --force, then re-apply the edits
  2. Keep customizations outside the managed skill directory and re-integrate after update
  3. If edits are unwanted, just use --force directly

Example fix

# before
rxjs-migrate-skill update --harness claude
# after
cp -r .claude/skills/rxjs-migrate /tmp/skill-backup
rxjs-migrate-skill update --harness claude --force
Defensive patterns

Strategy: try-catch

Validate before calling

const modified = await detectModifiedSkillCopy(targetPath); // compare digest vs canonical before updating

Try / catch

try { updateSkill(opts); } catch (e) { if (e instanceof Error && e.message.includes('locally modified')) { /* back up, then retry with force: true */ } throw e; }

Prevention

When it happens

Trigger: Running rxjs-migrate-skill update after hand-editing the installed SKILL.md or harness files, without --force.

Common situations: Teams customizing the installed skill then upgrading @rxjs/migrate; the update would revert their changes.

Related errors


AI-assisted analysis of ReactiveX/rxjs@54796b38a5 (2026-08-28). Data as JSON: /api/errors/b25b801500376f1f. Report an issue: GitHub.