FilOzone / FilOzone/synapse-sdk
fix: preserve InvalidUploadSizeError through store/upload error chain (not "Network request failed")
- 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
Assessment
This issue has not been assessed yet.