Skip to content

[Bug]: helia graph walkers end the walk cleanly when a block load fails #32

Description

@SgtPooki

Description: @helia/utils AbstractGraphWalker.walk runs block loads as queue jobs. When a load fails, the job's rejection is routed via queue.add(...).catch(err => gen.throw(err)), but the queue going idle can end the generator first — the consumer sees a clean end of stream, and the gen.throw on the finished generator surfaces the error as an unhandled rejection instead. The race goes both ways: sometimes the error propagates, sometimes the walk truncates silently. Any CAR assembled through these walkers (@helia/car export, @helia/verified-fetch CAR responses) can under-represent the DAG with no error.

Steps to Reproduce: load the pinned 21-block CAR (test/commp-piece-cid-regression.test.ts) into a MemoryBlockstore, delete one mid leaf, export via @helia/car with SubgraphExporter + depthFirstWalker and an exact block filter, drain the stream.

Expected: the export rejects with the load error.

Actual: the stream ends at 525,472 of 5,010,728 bytes with no error; NotFoundError fires later as an unhandled rejection.

Environment: @helia/utils 2.5.2, @helia/car 5.4.2, Node 26.

Additional Context: no exposure in current code — ipfs2foc-core/car-export drives its own traversal, so a failed load rejects the export deterministically. Tracked so the constraint stays visible (nothing in the commitment path may return to the upstream walkers until this is fixed upstream) and so the upstream report can lift this repro. The unhandledRejection orphan guard in src/verified-fetch.ts absorbs this same leak on the fallback path.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    Status
    📌 Triage

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions