affaan-m/ECC · error
Another Nasiko lifecycle operation is already in progress…
Error message
Another Nasiko lifecycle operation is already in progress; inspect ${lockPath} before recovering a stale lock. What it means
After finding an existing lock, acquireLifecycleLock checks whether the recorded pid is alive. If no valid lock metadata could be read (existing is null) or the recorded owner process is still running, stale-lock recovery is refused and this error is thrown — a live operation or an unreadable lock must not be force-removed.
Solutions
- Wait for the other operation to finish, then retry.
- Inspect the lock file at the path in the message (cat it, check pid/startedAt) and confirm whether the owner is alive (`ps -p <pid>`).
- If the pid is dead but metadata is corrupt (so recovery is blocked), manually delete the lock file and retry.
- Ensure only one lifecycle operation per install directory runs at a time in your tooling.
Example fix
// before
cat ~/.local/bin/.ecc-nasiko-lifecycle.lock # {"pid":12345,...}
installNasiko({ yes: true }) // throws while 12345 alive
// after
wait $PID_OF_OTHER_JOB
rm -f ~/.local/bin/.ecc-nasiko-lifecycle.lock # only if pid is dead/corrupt
installNasiko({ yes: true }) Defensive patterns
Strategy: try-catch
Validate before calling
const lockPath = path.join(installDir, '.ecc-nasiko-lifecycle.lock')
if (fs.existsSync(lockPath)) {
const { pid } = JSON.parse(fs.readFileSync(lockPath, 'utf8'))
let alive = false
try { process.kill(pid, 0); alive = true } catch (e) { alive = e.code !== 'ESRCH' }
if (alive) throw new Error(`wait for pid ${pid} to finish before installing`)
} Try / catch
try {
await installNasiko({ yes: true })
} catch (e) {
if (e.message.includes('already in progress')) {
const m = e.message.match(/inspect (\S+) before/)
const lock = JSON.parse(fs.readFileSync(m[1], 'utf8'))
console.error(`Operation running as pid ${lock.pid} since ${lock.startedAt}`)
}
throw e
} Prevention
- Never run two lifecycle operations against the same installDir simultaneously.
- Use a CI concurrency group to prevent overlapping install jobs.
- If a crash leaves a corrupt lock, verify the pid is dead, delete the lock manually, and retry.
When it happens
Trigger: installNasiko/uninstallNasiko while another operation currently holds the lock with a live pid; or the lock file exists but inspectLifecycleLock returns null (corrupt/oversized/invalid JSON content) so recovery is blocked defensively.
Common situations: Two developers running installs simultaneously; a CI job overlapping a local install; a lock file corrupted by a crash mid-write (truncated JSON) that the library refuses to auto-delete.
Related errors
- Another ECC process is updating Claude settings
- Another Nasiko lifecycle operation won lock acquisition
- Another Nasiko lifecycle operation won stale-lock recovery
- capsule.busy
- capsule.lock_lost
AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16).
Data as JSON: /api/errors/708a761c631e8f44.
Report an issue: GitHub.
Appendix: source
Thrown at scripts/lib/nasiko-release.js:364
}
let existing;
try { existing = inspectLifecycleLock(lockPath, fileSystem); }
catch (error) {
if (error.code === 'ENOENT') {
try { return createLifecycleLock(lockPath, fileSystem); }
catch (retryError) {
if (retryError.code === 'EEXIST') {
throw new Error(`Another Nasiko lifecycle operation won lock acquisition: ${lockPath}.`);
}
throw retryError;
}
}
throw error;
}
const isProcessAlive = options.isProcessAlive || processIsAlive;
if (!existing || isProcessAlive(existing.metadata.pid)) {
throw new Error(`Another Nasiko lifecycle operation is already in progress; inspect ${lockPath} before recovering a stale lock.`);
}
if (!removeLockIfOwned(lockPath, existing.stats, fileSystem)) {
throw new Error(`Nasiko lifecycle lock changed during stale-owner recovery: ${lockPath}.`);
}
try {
return createLifecycleLock(lockPath, fileSystem);
} catch (error) {
if (error.code === 'EEXIST') {
throw new Error(`Another Nasiko lifecycle operation won stale-lock recovery: ${lockPath}.`);
}
throw error;
}
}
async function installNasiko(options = {}, dependencies = {}) {
const version = options.version || 'v0.1.0';
const base = getQualifiedRelease(version, dependencies.platform || process.platform, dependencies.arch || process.arch);
const release = dependencies.releaseOverride ? { ...base, ...dependencies.releaseOverride } : base;View on GitHub (pinned to 8321021c54)