affaan-m/ECC · error
Nasiko installation requires explicit --yes consent.
Error message
Nasiko installation requires explicit --yes consent.
What it means
installNasiko performs no filesystem changes during a dry run, but a real installation mutates the install directory and downloads a binary. To prevent accidental installs, the library requires options.yes to be explicitly truthy; otherwise it throws this consent error before creating anything.
Solutions
- Pass yes: true in the options object when you intend a real install.
- On the CLI, add the --yes flag to the install command.
- Keep dryRun true while previewing; flip it off together with adding yes: true.
- Audit wrapper scripts to ensure the consent flag is forwarded to installNasiko.
Example fix
// before
await installNasiko({ version: 'v0.1.0', installDir: '/usr/local/bin' }) // throws
// after
await installNasiko({ version: 'v0.1.0', installDir: '/usr/local/bin', yes: true }) Defensive patterns
Strategy: validation
Validate before calling
function assertInstallConsent(options) {
if (!options.dryRun && !options.yes) {
throw new Error('real install requires { yes: true } or the --yes CLI flag')
}
}
assertInstallConsent(myOptions)
await installNasiko(myOptions) Type guard
const hasInstallConsent = (o) => Boolean(o && o.yes) || Boolean(o && o.dryRun)
Try / catch
try {
await installNasiko(opts)
} catch (e) {
if (e.message.includes('explicit --yes consent')) {
return installNasiko({ ...opts, yes: await promptForConfirmation() })
}
throw e
} Prevention
- Always pass yes: true (or --yes) whenever dryRun is false.
- Never rely on defaults: installNasiko defaults to a real install when dryRun is omitted.
- Wrap installNasiko in a helper that validates consent before calling.
- In CI, set the consent flag explicitly rather than relying on interactive prompts.
When it happens
Trigger: Calling installNasiko({ version, installDir, dryRun: false }) — or omitting dryRun — without options.yes: true; CLI paths that failed to forward the --yes flag into the options object.
Common situations: Scripting the library API after testing with dryRun (dryRun returns the plan and never reaches the consent check); forgetting to pass --yes through a wrapper script; interactive prompts skipped in CI.
Understand the failure class
Background: "--flag is required" and "must specify" CLI errors: how missing-required-flag validation works and how to fix it — this error's family across 20 libraries.
Related errors
- explicit --consent-to-openai is required
- Legacy language arguments cannot be combined with…
- Nasiko uninstall requires explicit --yes consent.
- No install profile, module IDs, included components, or…
- A normalized install request is required
AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16).
Data as JSON: /api/errors/f6c18d852c847833.
Report an issue: GitHub.
Appendix: source
Thrown at scripts/lib/nasiko-release.js:387
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;
const installDirectory = validateInstallDirectory(options.installDir || defaultInstallDirectory(release, dependencies.environment || process.env, dependencies.homeDirectory || os.homedir()));
const destination = path.join(installDirectory, release.binaryName);
const plan = { dryRun: Boolean(options.dryRun), version, platform: release.os, architecture: release.arch, manifestDigest: release.manifestDigest, binaryDigest: release.binaryDigest, registryOrigin: REGISTRY_ORIGIN, destination, license: release.license, sourceUrl: release.sourceUrl };
if (options.dryRun) return plan;
if (!options.yes) throw new Error('Nasiko installation requires explicit --yes consent.');
fs.mkdirSync(installDirectory, { recursive: true, mode: 0o755 });
assertPrivateInstallDirectory(installDirectory);
const releaseLock = acquireLifecycleLock(installDirectory);
const metadataPath = metadataPathFor(destination);
let destinationOwned = false;
let metadataOwned = false;
try {
const existing = inspectInstalledNasiko(destination);
if (existing.installed) {
if (existing.qualified && existing.version === version) return { ...plan, dryRun: false, installed: true, reused: true };
throw new Error('An unqualified or incompatible Nasiko executable or receipt already exists at the destination.');
}
const retrieve = dependencies.fetchBytes || fetchBytes;
const manifestBytes = await retrieve(`${REGISTRY_ORIGIN}/v2/${REPOSITORY}/manifests/${release.manifestDigest}`, { accept: 'application/vnd.oci.image.manifest.v1+json', maxBytes: MAX_MANIFEST_BYTES });
assertDigest(manifestBytes, release.manifestDigest, 'Nasiko manifest');
const layer = validateManifest(manifestBytes);
const archiveBytes = await retrieve(`${REGISTRY_ORIGIN}/v2/${REPOSITORY}/blobs/${layer.digest}`, { maxBytes: MAX_ARCHIVE_BYTES });
if (archiveBytes.length !== layer.size) throw new Error('Nasiko archive size mismatch.');View on GitHub (pinned to 8321021c54)