Skip to content

A failed semantic extraction chunk still writes a manifest entry, so the file is never retried #3093

Open

Description

@jvzelst-tech

What happened

graphify extract <path> --backend gemini printed a chunk failure, then reported success and exited 0:

[graphify] chunk 1/1 failed: Gemini/Kimi/Ollama/OpenAI-compatible extraction
requires the openai package. Run: pip install openai
[graphify extract] wrote .../graphify-out/graph.json: 2628 nodes, 3673 edges, 193 communities
[graphify extract] incremental summary: 301 files cached/unchanged, 1 re-extracted, 0 deleted

Note 1 re-extracted — the file whose only chunk failed is counted as re-extracted.

The document was then written into manifest.json with a current content hash. Every subsequent
incremental run treats it as already extracted and skips it. Installing the missing dependency and
re-running does not recover it: detect_incremental sees a matching hash and reports nothing to do.

I only recovered the file by deleting its manifest entry by hand. Had I trusted the exit code, that
document would have been permanently absent from the graph while every indicator reported success.

Why this is the worst of the failure modes

A transient, entirely recoverable error (a missing optional dependency) is converted into permanent,
silent data loss. There is no later signal: the graph looks plausible, the run exits 0, and the
manifest asserts the file is done.

Expected

  1. A file whose extraction chunk failed must not be recorded in the manifest.
  2. A run in which any chunk failed should exit non-zero.
  3. Ideally the summary line should distinguish extracted from failed rather than counting both as
    re-extracted.

Environment

graphifyy 0.7.15 · Python 3.13 · macOS · corpus of 205 markdown documents.

Activity

  1. abhay-codes07 commented on Aug 26, 2026

    @abhay-codes07
    Contributor

    Checked this against 0.9.50 (the report is from 0.7.15); both halves are handled now.

    1. The manifest is not stamped for a failed chunk. cli._stamped_manifest_files only stamps a semantic file that actually produced output; a file whose chunk failed has no source_file entry in the result and keeps an empty semantic_hash, so detect_incremental re-queues it on the next run (Files in failed semantic chunks are permanently skipped on re-run #933; tests/test_extract_cli.py pins that a zero-output doc stays unstamped). The same applies to a chunk that came back truncated.

    2. The exit code. Your exact case — chunk 1/1 failed — is "every chunk failed", and that path now prints error: all semantic chunks failed for backend '…' … If you see 'requires the X package', run pip install X and retry and exits 1 before anything is written (test_extract_exits_nonzero_when_all_semantic_chunks_fail). When only some chunks fail the run marks itself incomplete: the write falls back to the shrink guard instead of forcing, and a refused write exits non-zero with the manifest unstamped. A partial run that is not smaller than the existing graph still writes and exits 0 with the failed files left for the next run, which is deliberate (Files in failed semantic chunks are permanently skipped on re-run #933) — that is the one remaining gap between the behaviour and your expectation 2, and it is a design choice rather than a defect.

    The 1 re-extracted count in the summary is still what it was; that is the cosmetic third point.

  2. nothariharan commented on Oct 26, 2026

    @nothariharan
    Contributor

    Checked on v8 at 92741d1: both halves are fixed. A file whose chunk failed or was omitted keeps an empty semantic_hash and is cleared from the manifest (detect.py ~2770), so the next --update re-queues it. When every semantic chunk fails, graphify extract exits 1 instead of writing an AST-only graph (cli.py ~4538). The fix was also reproduced on 0.9.50 above. The only leftover is the 1 re-extracted wording in the summary line, which is cosmetic. Safe to close.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions