FilOzone / FilOzone/synapse-sdk

fix: preserve InvalidUploadSizeError through store/upload error chain (not "Network request failed")

Open
#841 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
TypeScript
Stars
25
Forks
32
Avg merge
3d 4h
Merged PRs (30d)
22

Description

## Summary

When a streaming upload fails because the packed piece/CAR is below the SP minimum size, the actionable `InvalidUploadSizeError` is buried under generic `Network request failed` / `StorageContext store failed` messages by the time it reaches SDK consumers (e.g. filecoin-pin CLI).

Users see an opaque network failure instead of the real size constraint.

## Expected behavior

Consumers should receive (or be able to surface) the underlying `InvalidUploadSizeError` message, e.g.:

```
Invalid upload size.

Details: Size 125 bytes is below minimum allowed size of 127 bytes or exceeds maximum allowed size of ...
```

## Actual behavior

filecoin-pin (and any SDK consumer displaying `StoreError.message`) shows something like:

```
Failed to store on primary provider 2 (https://calib2.ezpdpz.net)

Details: StorageContext store failed: Failed to store piece on service provider - Network request failed
```

The real cause is only visible by walking the nested `cause` chain (or with debug logging).

## Error chain (observed)

1. `InvalidUploadSizeError` — thrown in `@filoz/synapse-core` streaming upload when `bytesUploaded < MIN_UPLOAD_SIZE` (127 bytes) (`upload-streaming.ts` `TransformStream.flush`)
2. `NetworkError` — `Network request failed` (stream error during PUT to `/pdp/piece/uploads/{uuid}`)
3. `Error` via `createError()` — `StorageContext store failed: Failed to store piece on service provider - Network request failed` (`storage/context.ts`)
4. `StoreError` — `Failed to store on primary provider …` with `Details:` taken from immediate cause message, not the deepest `SynapseError` (`storage/manager.ts`)

`StoreError` / `SynapseError` currently populate `details` from the **immediate** `cause.message`, so the useful `InvalidUploadSizeError.details` never surfaces.

## How to reproduce

### Via filecoin-pin (easiest end-to-end)

From a filecoin-pin checkout with calibration credentials (`PRIVATE_KEY`, etc. in `.env`):

```bash
# A lone `date` line packs to a ~125-byte CAR — below the 127-byte minimum.
TMPFILE=$(mktemp) && date > "$TMPFILE" && \
LOG_LEVEL=debug NODE_DEBUG=fetch \
npx tsx src/cli.ts add "$TMPFILE" --network calibration --provider-id 2
```

**Observe:**
- User-facing failure: `Network request failed`
- `NODE_DEBUG=fetch` shows HTTP 201 on `POST …/pdp/piece/uploads`, then failed `PUT …/pdp/piece/uploads/{uuid}` with `Invalid upload size`
- Debug JSON log includes nested cause: `InvalidUploadSizeError` with full size details

Provider 2 (`calib2.ezpdpz.net`) ping succeeds; this is not connectivity.

### Minimal SDK-level repro (conceptual)

Any `synapse.storage.upload()` / `StorageContext.store()` call with streaming body whose final size is `< SIZE_CONSTANTS.MIN_UPLOAD_SIZE` (127) against a provider enforcing that minimum should reproduce the wrapped error chain.

## Suggested fixes (synapse layer)

Any of these (or a combination) would address the root cause:

1. **synapse-core**: Do not wrap `InvalidUploadSizeError` in `NetworkError` when the upload stream fails on size validation; preserve the original error (or set it as `cause` on a typed error that retains `details`).
2. **synapse-sdk `createError()`**: When wrapping, walk the `cause` chain for the deepest `SynapseError` and prefer its `details` / `shortMessage` in the outer message.
3. **`StoreError` construction** (`storage/manager.ts`): When primary `store()` fails, attach root-cause `details` from the nested chain (similar to how `SynapseError` could be enhanced globally).

## Fallback if this is rejected at the synapse layer

If maintainers prefer **not** to change synapse-sdk/synapse-core error propagation, the work should still be tracked in **filecoin-pin** (either move this issue there or open a sibling issue) to:

- Walk the `cause` chain in CLI upload paths (`add`, `import`) — same pattern as existing `describeLockupShortfall()` for `InsufficientLockupFunds`
- Surface known errors like `InvalidUploadSizeError` with actionable hints (e.g. pad test payloads past CAR overhead; see filecoin-pin `DEVELOPMENT.md`)

That would be a consumer-side workaround, not a root fix for other SDK users.

## Context

Discovered while testing calibration uploads with filecoin-pin’s `date > $TMPFILE` one-liner. CAR overhead can push a tiny unique payload just under the SP minimum; the misleading network error made this hard to diagnose without `LOG_LEVEL=debug` + `NODE_DEBUG=fetch`.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.