anthropics/skills · warning · ValueError

relationship target is not a POSIX part name: {target!r}

Error message

relationship target is not a POSIX part name: {target!r}

What it means

opc_target() normalizes an OOXML relationship target into a POSIX package part name. It rejects any target containing a backslash with this ValueError: OPC part names must use forward slashes, and a backslash usually means a producer wrote a Windows filesystem path into the .rels XML.

Source

Thrown at skills/xlsx/scripts/office/helpers/__init__.py:35

}

_SCHEME_RE = re.compile(r"^[A-Za-z][A-Za-z0-9+.\-]*:")

SLIDE_REL_TYPE = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/slide"


def opc_target(target: str, source_part: str, target_mode: str = "") -> str | None:
    if not target:
        return None
    if target_mode.lower() == "external":
        return None
    if _SCHEME_RE.match(target):
        return None

    target = urllib.parse.unquote(target)

    if "\\" in target:
        raise ValueError(f"relationship target is not a POSIX part name: {target!r}")

    if target.startswith("/"):
        joined = target.lstrip("/")
    else:
        joined = posixpath.join(posixpath.dirname(source_part), target)

    parts: list[str] = []
    for segment in posixpath.normpath(joined).split("/"):
        if segment in ("", "."):
            continue
        if segment == "..":
            if not parts:
                raise ValueError(f"relationship target escapes the package: {target!r}")
            parts.pop()
        else:
            parts.append(segment)

    if not parts:

View on GitHub (pinned to f6656c1256)

Solutions

  1. Inspect the offending .rels: unzip the file and grep for 'Target="[^"]*\\' to find the entry
  2. Rewrite targets to forward slashes (folder/file.xml) — either in the source tool or with a small fix-up pass before loading
  3. If you do not control the producer, pre-normalize a copy of the archive (replace \\ with / in *.rels) and load that

Example fix

# before (inside a .rels file)
<Relationship Target="sheets\\sheet1.xml" .../>
# after
<Relationship Target="sheets/sheet1.xml" .../>
Defensive patterns

Strategy: validation

Validate before calling

def rels_targets_are_posix(xlsx_path: str) -> bool:
    import zipfile, re
    with zipfile.ZipFile(xlsx_path) as zf:
        for n in zf.namelist():
            if n.endswith(".rels"):
                data = zf.read(n).decode("utf-8", "replace")
                for m in re.finditer(r'Target="([^"]*)"', data):
                    if "\\" in m.group(1):
                        return False
    return True

Try / catch

try:
    part = opc_target(target, source_part, mode)
except ValueError as e:
    if "not a POSIX part name" in str(e):
        part = opc_target(target.replace("\\", "/"), source_part, mode)  # only for trusted inputs
    else:
        raise

Prevention

When it happens

Trigger: Loading an xlsx/pptx/docx whose *.rels contains Target="folder\file.xml" or Target="..\shared\styles.xml"; files round-tripped through tools that call Path() on targets and stringify back with os.sep on Windows; hand-authored or third-party-generated packages with backslash separators.

Common situations: Spreadsheets exported by niche ERP/Java/legacy tools; files manipulated on Windows by scripts that joined paths with backslashes before writing rels; otherwise valid documents that only Microsoft's lenient reader opens.

Related errors


AI-assisted analysis of anthropics/skills@f6656c1256 (2026-08-14). Data as JSON: /api/errors/919acd924d497a3a. Report an issue: GitHub.