MemPalace/mempalace · error · IOError

Could not read {filepath}: symlinked files are skipped

Error message

Could not read {filepath}: symlinked files are skipped

What it means

Error "Could not read {filepath}: symlinked files are skipped" thrown in MemPalace/mempalace.

Source

Thrown at mempalace/normalize.py:130

    # Narrow shape — a bare "(ctrl+o to expand)" in user prose stays intact.
    text = re.sub(r"\s*\[\d+\s+tokens?\]\s*\(ctrl\+o to expand\)", "", text)
    # Collapse runs of blank lines created by the removals
    text = re.sub(r"\n{4,}", "\n\n\n", text)
    return text.strip()


def _read_transcript_file(filepath: str) -> str:
    """Read a transcript source file with the same safety checks normalize()
    and normalize_conversations() both need: no symlinks, regular files only,
    size-capped, BOM-tolerant.
    """
    # O_NONBLOCK keeps the "not a regular file" check below reachable: a
    # blocking open of a FIFO waits in the kernel for a writer, so the
    # S_ISREG test never runs. See ``miner._read_text_no_follow``, including
    # why the EAGAIN branch re-checks the type and retries without the flag.
    flags = os.O_RDONLY | getattr(os, "O_NOFOLLOW", 0) | getattr(os, "O_NONBLOCK", 0)
    if os.path.islink(filepath):
        raise IOError(f"Could not read {filepath}: symlinked files are skipped")
    fd = -1
    try:
        try:
            fd = os.open(filepath, flags)
        except OSError as exc:
            if exc.errno != errno.EAGAIN or not stat.S_ISREG(os.lstat(filepath).st_mode):
                raise
            fd = os.open(filepath, flags & ~getattr(os, "O_NONBLOCK", 0))
        file_stat = os.fstat(fd)
        if not stat.S_ISREG(file_stat.st_mode):
            # Text stays prefix-free: this raise is inside the ``try``, so the
            # ``except OSError`` below composes "Could not read <path>: ...".
            raise IOError("not a regular file")
        if file_stat.st_size > 500 * 1024 * 1024:  # 500 MB safety limit
            # Prefix-free for the same reason as the branch above.
            raise IOError(f"file too large ({file_stat.st_size // (1024 * 1024)} MB)")
        with os.fdopen(fd, "r", encoding="utf-8-sig", errors="replace") as f:
            fd = -1

View on GitHub (pinned to 06cb6987f0)

Solutions

  1. Point at the real file instead of a symlink, or copy the content to a regular file

When it happens

Trigger: Thrown at mempalace/normalize.py:130 when the library encounters an invalid state.

Common situations: Symlinked transcript files are skipped by design.


AI-assisted analysis of MemPalace/mempalace@06cb6987f0 (2026-08-15). Data as JSON: /api/errors/82dbb792e90844a2. Report an issue: GitHub.