affaan-m/ECC · error

Published Nasiko binary size mismatch.

Error message

Published Nasiko binary size mismatch.

What it means

Thrown after writing the Nasiko binary to disk (exclusive 'wx' open at 0700) when the file size reported by fs.fstatSync differs from the in-memory binary buffer length. It confirms the fsync'd file on disk matches what was verified in memory before the install is reported successful.

Solutions

  1. Check free disk space on the target filesystem; free space if full and retry the install.
  2. Ensure no concurrent process writes the same destination; the 'wx' open prevents concurrent creates but not post-open interference, so serialize installs.
  3. Retry the install — transient I/O errors can cause short writes.
  4. If testing with dependency-injected fs, fix the mock so writeFileSync/fstatSync report consistent sizes.

Example fix

// before
fs.writeFileSync(descriptor, binary);
fs.fsyncSync(descriptor);
// after (check write return + space)
const written = fs.writeFileSync(descriptor, binary);
fs.fsyncSync(descriptor);
if (fs.statSync(destination).size !== binary.length) throw new Error('short write — check disk space');
Defensive patterns

Strategy: try-catch

Validate before calling

import fs from 'node:fs';
import { statfsSync } from 'node:fs';
const space = statfsSync(path.dirname(destination));
if (space.bavail * space.bsize < binaryLength) throw new Error('insufficient disk space');

Type guard

null

Try / catch

try {
  await installNasiko({ version });
} catch (e) {
  if (e.message === 'Published Nasiko binary size mismatch.') {
    // free disk space / stop concurrent writers, then retry
    await installNasiko({ version });
  } else throw e;
}

Prevention

When it happens

Trigger: fs.writeFileSync(descriptor, binary) plus fsync produced a file whose stat size !== binary.length — typically caused by concurrent writers to the same path, a full disk, a custom fs mock in dependencies, or filesystem corruption.

Common situations: Disk-full conditions during install; another process racing to write the same destination path; running under a virtualized/partial fs shim in tests that doesn't persist all bytes.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16). Data as JSON: /api/errors/c37d3fa0262e3fa4. Report an issue: GitHub.

Appendix: source

Thrown at scripts/lib/nasiko-release.js:415

      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.');
    assertDigest(archiveBytes, layer.digest, 'Nasiko archive');
    const binary = (dependencies.extractBinary || extractQualifiedTarGzip)(archiveBytes, release.binaryName);
    assertDigest(binary, release.binaryDigest, 'Nasiko binary');
    if (dependencies.beforePublish) dependencies.beforePublish(destination);
    const descriptor = fs.openSync(destination, 'wx', 0o700);
    destinationOwned = true;
    try {
      fs.writeFileSync(descriptor, binary);
      fs.fsyncSync(descriptor);
      if (fs.fstatSync(descriptor).size !== binary.length) throw new Error('Published Nasiko binary size mismatch.');
    } finally { fs.closeSync(descriptor); }
    const metadata = { version, platform: release.os, architecture: release.arch, manifestDigest: release.manifestDigest, artifactDigest: layer.digest, binaryDigest: release.binaryDigest, installedPath: destination, license: release.license, sourceUrl: release.sourceUrl };
    (dependencies.writeMetadata || writeMetadataExclusive)(metadataPath, metadata);
    metadataOwned = true;
    return { ...plan, dryRun: false, installed: true, reused: false, artifactDigest: layer.digest };
  } catch (error) {
    if (metadataOwned) fs.rmSync(metadataPath, { force: true });
    if (destinationOwned) fs.rmSync(destination, { force: true });
    throw error;
  } finally { releaseLock(); }
}

function uninstallNasiko(options = {}, dependencies = {}) {
  const version = options.version || 'v0.1.0';
  const release = getQualifiedRelease(version, dependencies.platform || process.platform, dependencies.arch || process.arch);
  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, destination };

View on GitHub (pinned to 8321021c54)