ruvnet/ruflo · error · Error
Pinata upload failed: ${response.status} ${error}
Error message
Pinata upload failed: ${response.status} ${error} What it means
uploadToPinata() POSTs the multipart body to https://api.pinata.cloud/pinning/pinFileToIPFS with pinata_api_key / pinata_secret_api_key headers (the legacy v1 key scheme). A non-ok response is converted into this error carrying the status and Pinata's response text. Typical statuses: 401 invalid/expired key pair, 403 key not authorized for pinning, 429 rate/quota limits, 5xx Pinata outages.
Source
Thrown at v3/@claude-flow/cli/src/transfer/ipfs/upload.ts:180
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('https://api.pinata.cloud/pinning/pinFileToIPFS', {
method: 'POST',
headers: {
'pinata_api_key': apiKey,
'pinata_secret_api_key': apiSecret,
'Content-Type': `multipart/form-data; boundary=${boundary}`,
},
body,
});
if (!response.ok) {
const error = await response.text();
throw new Error(`Pinata upload failed: ${response.status} ${error}`);
}
const result = await response.json() as { IpfsHash: string; PinSize: number };
const cid = result.IpfsHash;
const gateway = options.gateway || 'https://gateway.pinata.cloud';
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
- Match the status: 401/403 -> regenerate the key pair in the Pinata console and update both env vars; 429 -> back off and retry with fewer concurrent uploads
- Verify the pair is consistent (old key with new secret fails as 401)
- For 5xx, retry with exponential backoff — Pinata outages are usually brief
- Fall back to another configured provider (web3.storage token or local IPFS_API_URL node) if Pinata keeps rejecting
Example fix
// before
await uploadToIPFS(content, { provider: 'pinata' }); // 401 -> Pinata upload failed: 401 ...
// after
const isRetryable = (msg: string) => /Pinata upload failed: (429|5\d\d)/.test(msg);
for (let attempt = 0; ; attempt++) {
try { return await uploadToIPFS(content, { provider: 'pinata' }); }
catch (e) {
if (attempt < 3 && isRetryable(String(e?.message))) {
await new Promise(r => setTimeout(r, 2 ** attempt * 1000)); continue;
}
throw e;
}
} Defensive patterns
Strategy: fallback
Try / catch
const isPinataFailure = (e: unknown) => /Pinata upload failed: (\d+)/.test(String((e as Error)?.message));
try {
result = await uploadToIPFS(content, { provider: 'pinata' });
} catch (e) {
if (!isPinataFailure(e)) throw e;
const status = Number(/: (\d+)/.exec(String((e as Error).message))?.[1]);
if (status === 429 || status >= 500) {
await new Promise(r => setTimeout(r, 2 ** attempt * 1000)); // retryable
continue;
}
result = await uploadToIPFS(content, { provider: 'web3' }); // 401/403: fall back, then fix keys Prevention
- Parse the HTTP status out of the message to route 429/5xx to retry and 401/403 to credential rotation
- Throttle bulk uploads to stay under Pinata rate limits instead of reacting to 429s
- Keep a fallback provider configured so a single pinning outage does not stop transfers
When it happens
Trigger: Uploading with a revoked or mistyped PINATA_API_KEY/SECRET pair; hitting free-tier rate limits during bulk pattern transfers; using legacy v1 API keys on endpoints that now demand JWT signatures; transient Pinata 5xx.
Common situations: Regenerated keys in the Pinata console but stale env vars still loaded; bulk uploads of many CFP files tripping 429; corporate egress filtering returning 403; legacy key auth deprecated in favor of Pinata JWT gateways.
Related errors
- Web3.storage upload failed: ${response.status} ${error}
- Pinata upload failed (HTTP ${res.status}): ${JSON.stringify(
- Pinata list failed (HTTP ${res.status}): ${JSON.stringify(re
- Pinata pin failed (HTTP ${res.status}): ${JSON.stringify(res
- Pinata API credentials not found. Set PINATA_API_KEY and PIN
AI-assisted analysis of ruvnet/ruflo@fa13ee4ad6 (2026-08-18).
Data as JSON: /api/errors/8457aea5d6b471c7.
Report an issue: GitHub.