ruvnet/ruflo · error · Error
Web3.storage upload failed: ${response.status} ${error}
Error message
Web3.storage upload failed: ${response.status} ${error} What it means
uploadToWeb3Storage() POSTs a multipart body to `${endpoint}/upload` (default https://api.web3.storage/upload) with an Authorization: Bearer token. When the HTTP response is not ok, the response body text is appended to the status code and thrown. So this is the upstream API rejecting the request: 401 for a bad/expired token, 4xx for malformed payloads, 5xx for outages. Note web3.storage's classic upload API has been deprecated/sunset by Protocol Labs, so non-200s are now common with old tokens.
Source
Thrown at v3/@claude-flow/cli/src/transfer/ipfs/upload.ts:115
Buffer.from(`--${boundary}\r\n`),
Buffer.from(`Content-Disposition: form-data; name="file"; filename="${name}"\r\n`),
Buffer.from(`Content-Type: application/json\r\n\r\n`),
content,
Buffer.from(`\r\n--${boundary}--\r\n`),
]);
const response = await fetch(`${endpoint}/upload`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': `multipart/form-data; boundary=${boundary}`,
},
body,
});
if (!response.ok) {
const error = await response.text();
throw new Error(`Web3.storage upload failed: ${response.status} ${error}`);
}
const result = await response.json() as { cid: string };
const cid = result.cid;
const gateway = options.gateway || 'https://w3s.link';
console.log(`[IPFS] Upload complete!`);
console.log(`[IPFS] CID: ${cid}`);
return {
cid,
size: content.length,
gateway,
pinnedAt: new Date().toISOString(),
url: `${gateway}/ipfs/${cid}`,
};
}
View on GitHub (pinned to fa13ee4ad6)
Solutions
- Read the status code in the message: 401/403 means regenerate the token and update WEB3_STORAGE_TOKEN
- If it is a persistent failure on a legacy token, migrate providers — pinata (PINATA_API_KEY/PINATA_API_SECRET) or a local IPFS node (IPFS_API_URL) are built-in alternatives
- For 5xx, retry after a backoff interval
- Confirm the endpoint if you set a custom one via options.endpoint
Example fix
// before
const result = await uploadToIPFS(content, { provider: 'web3' }); // 401 -> Web3.storage upload failed: 401 ...
// after
let result;
try {
result = await uploadToIPFS(content, { provider: 'web3' });
} catch (e) {
if (/Web3\.storage upload failed/.test(String(e?.message))) {
result = await uploadToIPFS(content, { provider: 'pinata' }); // fallback provider
} else throw e;
} Defensive patterns
Strategy: fallback
Try / catch
const isWeb3Failure = (e: unknown) => /Web3\.storage upload failed: (\d+)/.test(String((e as Error)?.message));
try {
result = await uploadToIPFS(content, { provider: 'web3' });
} catch (e) {
if (!isWeb3Failure(e)) throw e;
const status = Number(/: (\d+)/.exec(String((e as Error).message))?.[1]);
if (status === 401 || status === 403) throw new Error('web3.storage token invalid — refresh WEB3_STORAGE_TOKEN'); // not retryable
result = await uploadToIPFS(content, { provider: 'pinata' }); // 4xx/5xx -> fall back to another provider Prevention
- Treat 401/403 as configuration errors (rotate the token) and only 5xx as retryable — never blind-retry auth failures
- Always configure a second provider (pinata or a local node via IPFS_API_URL) so uploads have a fallback path
- Log the status code from the message before choosing retry vs fallback
When it happens
Trigger: Uploading with an expired or revoked WEB3_STORAGE_TOKEN (401); uploading after the web3.storage classic service was deprecated (the endpoint no longer accepts uploads); oversized or malformed content producing 4xx; transient 5xx during an API incident.
Common situations: Tokens that worked historically now failing because the service shut down; free-tier limits hit; copied credentials from another account; corporate proxies returning 403/502 on the POST.
Related errors
- Pinata upload failed: ${response.status} ${error}
- Web3.storage token not found. Set WEB3_STORAGE_TOKEN environ
- Local IPFS upload failed: ${response.status} ${error}
- Pinata upload failed (HTTP ${res.status}): ${JSON.stringify(
- Pinata list failed (HTTP ${res.status}): ${JSON.stringify(re
AI-assisted analysis of ruvnet/ruflo@fa13ee4ad6 (2026-08-18).
Data as JSON: /api/errors/8a7ba18ff2430299.
Report an issue: GitHub.