nexu-io/open-design · error · SystemExit

[last30days] Cannot read --synthesis-file: {exc}

Error message

[last30days] Cannot read --synthesis-file: {exc}

What it means

read_synthesis_file() expands the user path and calls Path.read_text(encoding='utf-8'). On any OSError (file missing, permission denied, ISDIR, broken symlink, decode-adjacent read failure) it writes a `[last30days] Cannot read --synthesis-file: <exc>` line to stderr and re-raises as SystemExit(2). The exception object is interpolated verbatim so the underlying errno/path is visible.

Source

Thrown at design-templates/last30days/scripts/last30days.py:200

    slug = slugify(topic)
    extension = "json" if emit == "json" else "html" if emit == "html" else "md"
    raw_label = "raw-html" if emit == "html" else "raw"
    suffix_part = f"-{suffix}" if suffix else ""
    raw = path / f"{slug}-{raw_label}{suffix_part}.{extension}"
    try:
        home = _Path.home().resolve()
        relative = raw.relative_to(home)
        return f"~/{relative}"
    except ValueError:
        return str(raw)


def read_synthesis_file(path: str) -> str:
    try:
        return Path(path).expanduser().read_text(encoding="utf-8")
    except OSError as exc:
        sys.stderr.write(f"[last30days] Cannot read --synthesis-file: {exc}\n")
        raise SystemExit(2)


def persist_report(report: schema.Report) -> dict[str, int]:
    import store

    store.init_db()
    topic_row = store.add_topic(report.topic)
    topic_id = topic_row["id"]
    source_mode = ",".join(sorted(report.items_by_source)) or "v3"
    run_id = store.record_run(topic_id, source_mode=source_mode, status="running")
    try:
        findings = store.findings_from_report(report)
        counts = store.store_findings(run_id, topic_id, findings)
        store.update_run(
            run_id,
            status="completed",
            findings_new=counts["new"],
            findings_updated=counts["updated"],

View on GitHub (pinned to 5be4028344)

Solutions

  1. Check the path exists and is a regular file: `test -f <path>`.
  2. Check read permission: `ls -l <path>`; chmod if needed.
  3. Use an absolute path to avoid ambiguity.
  4. Ensure the file is UTF-8 decodable (the read uses encoding='utf-8').

Example fix

# before
python3.12 last30days.py --topic x --synthesis-file ~/pres/synth.mdr
# after (fix typo)
python3.12 last30days.py --topic x --synthesis-file ~/pres/synth.md
Defensive patterns

Strategy: validation

Validate before calling

from pathlib import Path
p = Path(path).expanduser()
if not p.is_file():
    raise FileNotFoundError(f'--synthesis-file not a readable file: {p}')
text = p.read_text(encoding='utf-8')

Try / catch

from pathlib import Path
try:
    synthesis = Path(path).expanduser().read_text(encoding='utf-8')
except OSError as exc:
    print(f'[last30days] Cannot read --synthesis-file: {exc}', file=sys.stderr)
    sys.exit(2)

Prevention

When it happens

Trigger: `--synthesis-file ~/notes/synth.md` where the file does not exist, is a directory, has no read permission, or is on an unreadable mount.

Common situations: Typo in the path; ~ not expanded by the shell because the arg was quoted oddly (the code does call expanduser, so this is rare); permissions locked down; file on a disconnected network mount; pointing at a directory by mistake.

Related errors


AI-assisted analysis of nexu-io/open-design@5be4028344 (2026-08-12). Data as JSON: /api/errors/089805eb38920233. Report an issue: GitHub.