Hmbown/CodeWhale · error

legacy import refused: symlink or size bound

Error message

legacy import refused: symlink or size bound

What it means

native_memory import_legacy() imports a legacy markdown memory file only if it is a regular file of at most 1 MiB. Symlinks and oversized files are refused with this error — a security/robustness guard against symlink tricks (importing arbitrary files) and memory blowups from huge inputs.

Solutions

  1. Replace the symlink with a real copy of the target file inside the workspace.
  2. Split or trim the legacy file to under 1 MiB before importing.
  3. Import only the relevant portion of an oversized legacy file.
  4. Verify the path with `ls -l` (or fs::symlink_metadata) to confirm it is a plain file under the size bound.

Example fix

// before: symlinked legacy file
ln -s ~/dotfiles/MEMORY.md ~/.codewhale/MEMORY.md

// after: real file copy under 1 MiB
cp ~/dotfiles/MEMORY.md ~/.codewhale/MEMORY.md && truncate -s 900K ~/.codewhale/MEMORY.md
Defensive patterns

Strategy: validation

Validate before calling

let meta = fs::symlink_metadata(path)?;
if meta.file_type().is_symlink() || meta.len() > 1024 * 1024 {
    return Err("legacy import requires a plain file under 1 MiB".into());
}

Prevention

When it happens

Trigger: Calling import_legacy on a path that is a symlink (symlink_metadata reports a symlink file type) or a regular file larger than 1024*1024 bytes.

Common situations: Legacy MEMORY.md symlinked into a dotfiles repo; a legacy notes file that grew past 1 MiB over years of use; pointing import at a directory-like symlink or a synced/virtual file reported as oversized.

Understand the failure class

Background: "File too large" / "file size exceeds limit" errors: why libraries cap file sizes and how to fix them — this error's family across 46 libraries.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22). Data as JSON: /api/errors/8f235d1a60ff7861. Report an issue: GitHub.

Appendix: source

Thrown at crates/tui/src/native_memory.rs:506

        };
        let access = Access::operator(scopes)?;
        let store = self.open_structured()?;
        // Entry surfaces show only live memory; candidates and reviewed-off
        // entries are visible in the Context Lens, not here.
        store
            .list(&access, None, limit)?
            .iter()
            .filter(|m| matches!(m.status, Status::Active | Status::Stale))
            .map(|m| self.hit(&store, &access, m, &Snapshot::default()))
            .collect()
    }
    pub fn import_legacy(&self, path: &Path) -> Result<bool> {
        if !path.is_file() {
            return Ok(false);
        }
        let meta = fs::symlink_metadata(path)?;
        if meta.file_type().is_symlink() || meta.len() > 1024 * 1024 {
            bail!("legacy import refused: symlink or size bound");
        }
        let text = fs::read_to_string(path)?;
        let scope = Self::owner_scope();
        let access = Access::operator(vec![scope.clone()])?;
        let mut store = self.open_structured()?;
        let report = codewhale_memory::import::markdown(
            &mut store,
            &access,
            &scope,
            "codewhale:legacy-memory",
            &text,
        )?;
        if !report.rejected.is_empty() {
            bail!(
                "legacy import left {} rejected notes unchanged; inspect before retry",
                report.rejected.len()
            );
        }

View on GitHub (pinned to 73e0f67d83)