stablyai/orca · error

${targetName} provider alias did not converge with the canon

Error message

${targetName} provider alias did not converge with the canonical update

What it means

In symlink shape, after the update, the script resolves the target provider's realpath and hashes it; the digest must equal currentSkill(targetName).packageDigest. If the alias still points somewhere but at stale content, it throws — the alias must converge to the canonical updated package.

Source

Thrown at config/scripts/verify-skill-update-roundtrip.mjs:218

        updatedAt: timestamp
      }
    }
  }
  const lockPath = path.join(stateHome, 'skills', '.skill-lock.json')
  await mkdir(path.dirname(lockPath), { recursive: true })
  await writeFile(lockPath, `${JSON.stringify(lock, null, 2)}\n`)

  // Why: this is the exact user-visible rail. A bare update would include
  // unrelated vendors, while this command must leave the control skill alone.
  execSkills(['update', targetName, '--global'])
  await assertCurrentCanonical(targetName)
  const targetProviderAfter = await packageDigestAt(await realpath(targetProvider))
  const targetProviderStat = await lstat(targetProvider)
  if (shape === 'symlink' && !targetProviderStat.isSymbolicLink()) {
    throw new Error(`${targetName} provider alias was replaced with an independent copy`)
  }
  if (shape === 'symlink' && targetProviderAfter !== currentSkill(targetName).packageDigest) {
    throw new Error(`${targetName} provider alias did not converge with the canonical update`)
  }
  if (
    shape === 'copy' &&
    targetProviderAfter !== targetProviderBefore &&
    targetProviderAfter !== currentSkill(targetName).packageDigest
  ) {
    throw new Error('Independent provider copy changed to an unexpected package identity')
  }
  if (shape === 'copy') {
    // Why: hosted 1.5.17 replaces copies with aliases while equivalent local runs
    // retain the copy. Both prove this input topology must remain ineligible.
    const outcome = targetProviderStat.isSymbolicLink()
      ? 'converged to an alias'
      : targetProviderAfter === targetProviderBefore
        ? 'remained a historical copy'
        : 'converged as a copy'
    console.log(`[skill-update-roundtrip] independent copy ${outcome}`)
  }

View on GitHub (pinned to 1136503c6a)

Solutions

  1. Inspect the provider symlink target (readlink) and the canonical placement digest to see which is stale.
  2. Confirm assertCurrentCanonical passed (canonical is up to date) before diagnosing the alias — if canonical is wrong, fix 289 first.
  3. File a CLI bug: an update that refreshes the canonical must also repoint existing symlinks at the new canonical.
  4. Pin to a CLI version whose update path repoints aliases correctly.
Defensive patterns

Strategy: validation

Validate before calling

// Pre-assert the symlink target will track the canonical directory:
import { readlinkSync } from 'node:fs'
import path from 'node:path'
function assertAliasTracksCanonical(providerPath, canonicalPath) {
  const target = readlinkSync(providerPath)
  const resolved = path.resolve(path.dirname(providerPath), target)
  if (resolved !== canonicalPath) {
    throw new Error(`Provider alias ${providerPath} -> ${resolved} does not track canonical ${canonicalPath}`)
  }
}
// If this fails before the update, the alias was already stale; fix the fixture first.

Prevention

When it happens

Trigger: The update rewrote the canonical placement but left the provider symlink pointing at the old target; the symlink is relative and points at a path that wasn't updated; realpath resolves to a cached/old checkout; the canonical digest itself is stale.

Common situations: Symlink target path drift between CLI versions; update writes the canonical to a versioned directory but the symlink still points at the previous version directory; partial update that touched the lock but not the alias target.

Related errors


AI-assisted analysis of stablyai/orca@1136503c6a (2026-08-12). Data as JSON: /api/errors/02dad5df5b4534e4. Report an issue: GitHub.