firecrawl/pdf-inspector · error · ModelStoreError::Io

could not allocate a unique model install file

Error message

could not allocate a unique model install file

What it means

create_temporary_file in src/vision/models.rs tries 16 times to create a unique '.{filename}.{pid}.{timestamp}.{seq}.part' file with create_new(true); if all 16 attempts collide with an existing file it returns ModelStoreError::Io with ErrorKind::AlreadyExists and message 'could not allocate a unique model install file'. This protects model installs: partial downloads are written to a .part file and atomically renamed, and this failure means the store could not reserve a scratch file.

Source

Thrown at src/vision/models.rs:570

            .duration_since(UNIX_EPOCH)
            .unwrap_or_default()
            .as_nanos();
        let path = root.join(format!(
            ".{filename}.{}.{}.{}.part",
            std::process::id(),
            timestamp,
            sequence
        ));
        match OpenOptions::new().create_new(true).write(true).open(&path) {
            Ok(file) => return Ok((path, file)),
            Err(source) if source.kind() == io::ErrorKind::AlreadyExists => continue,
            Err(source) => return Err(ModelStoreError::Io { path, source }),
        }
    }
    let path = root.join(format!(".{filename}.part"));
    Err(ModelStoreError::Io {
        path,
        source: io::Error::new(
            io::ErrorKind::AlreadyExists,
            "could not allocate a unique model install file",
        ),
    })
}

#[cfg(not(windows))]
fn replace_file_atomic(source: &Path, target: &Path) -> io::Result<()> {
    fs::rename(source, target)
}

#[cfg(windows)]
fn replace_file_atomic(source: &Path, target: &Path) -> io::Result<()> {
    use std::os::windows::ffi::OsStrExt;
    use windows_sys::Win32::Storage::FileSystem::{
        MoveFileExW, MOVEFILE_REPLACE_EXISTING, MOVEFILE_WRITE_THROUGH,
    };

View on GitHub (pinned to 636ca1a58b)

Solutions

  1. Clear stale '.{filename}.*.part' files from the model root directory (the store's sweep_stale_install_files normally does this) and retry the install.
  2. Point the model store root at a local filesystem (not NFS/network mount) where O_EXCL create_new works reliably.
  3. Check filesystem permissions and free space on the model root; a persistent EACCES/ENOSPC surfaces as ModelStoreError::Io too.
  4. If it recurs, report it — 16 collisions of pid+nanotimestamp+counter indicates a platform filesystem bug.

Example fix

# before (model root on NFS)
MODEL_STORE_ROOT=/mnt/nfs/models
# after
MODEL_STORE_ROOT=~/.cache/pdf-inspector/models
Defensive patterns

Strategy: retry

Validate before calling

// before model install: ensure root is a local, writable dir without stale part files
const fs = require('fs');
function prepareModelRoot(root) {
  fs.mkdirSync(root, { recursive: true });
  for (const f of fs.readdirSync(root)) {
    if (f.startsWith('.') && f.endsWith('.part')) fs.rmSync(`${root}/${f}`, { force: true });
  }
}

Type guard

function isTempAllocFailure(e) {
  return e instanceof Error && e.message.includes('could not allocate a unique model install file');
}

Try / catch

try {
  await store.ensureModel(name);
} catch (e) {
  if (isTempAllocFailure(e)) {
    cleanPartFiles(modelRoot);
    await store.ensureModel(name); // one retry after cleanup
  } else throw e;
}

Prevention

When it happens

Trigger: Downloading/installing a vision model into the model store when 16 consecutive create_new attempts all hit AlreadyExists — i.e. extreme filename collisions in the model root directory.

Common situations: A directory whose clock/timestamp resolution produces identical names (rare); a filesystem with broken create_new semantics (some network mounts, old NFS); leftover .part debris plus a frozen or wrapped counter; running many processes in lockstep on the same model root.


AI-assisted analysis of firecrawl/pdf-inspector@636ca1a58b (2026-09-05). Data as JSON: /api/errors/caffdbfb8e488a2a. Report an issue: GitHub.