ruvnet/ruflo · error · Error
Pinata pin failed (HTTP ${res.status}): ${JSON.stringify(res
Error message
Pinata pin failed (HTTP ${res.status}): ${JSON.stringify(res.data)} What it means
Thrown by RvfaPublisher.pin() when Pinata's POST /pinning/pinByHash returns a non-200 status. pin() asks Pinata to pin an existing CID by hash. The error embeds status and body for diagnosis.
Source
Thrown at v3/@claude-flow/cli/src/appliance/rvfa-distribution.ts:391
async list(): Promise<PublishedItem[]> {
const res = await pinataReq('GET', `${this.api}/data/pinList?status=pinned&pageLimit=100`, this.jwt);
if (res.status !== 200)
throw new Error(`Pinata list failed (HTTP ${res.status}): ${JSON.stringify(res.data)}`);
const d = res.data as { rows: Array<{
ipfs_pin_hash: string; metadata?: { name?: string }; size: number; date_pinned: string;
}> };
return (d.rows || []).map((r) => ({
cid: r.ipfs_pin_hash, name: r.metadata?.name || r.ipfs_pin_hash,
size: r.size, date: r.date_pinned,
}));
}
async pin(cid: string, name?: string): Promise<void> {
const body = Buffer.from(JSON.stringify({ hashToPin: cid, pinataMetadata: { name: name || cid } }));
const res = await pinataReq('POST', `${this.api}/pinning/pinByHash`, this.jwt, body, 'application/json');
if (res.status !== 200)
throw new Error(`Pinata pin failed (HTTP ${res.status}): ${JSON.stringify(res.data)}`);
}
}
// ── Convenience exports ──────────────────────────────────────
export function createPublisher(config?: Partial<PublishConfig>): RvfaPublisher {
return new RvfaPublisher({ pinataJwt: config?.pinataJwt, gatewayUrl: config?.gatewayUrl, apiUrl: config?.apiUrl });
}
export async function createAndVerifyPatch(
options: CreatePatchOptions,
): Promise<{ patch: Buffer; verification: PatchVerifyResult }> {
const patch = await RvfaPatcher.createPatch(options);
const verification = await RvfaPatcher.verifyPatch(patch);
return { patch, verification };
}
View on GitHub (pinned to 6b01dc5a68)
Solutions
- Validate the CID format (multibase, expected length for the hash) before calling pin().
- For 401/403: ensure the JWT has pinByHash/pinning permissions.
- For 409/duplicate: treat as success if the CID is already pinned (call list() to confirm).
- For 429/5xx: retry with backoff.
Defensive patterns
Strategy: validation
Validate before calling
function isValidCid(cid: string): boolean {
// Basic multibase/base58 or base32 CID check (v0 starts with 'Qm', v1 with 'b')
return /^(Qm[1-9A-HJ-NP-Za-km-z]{44}|b[a-z2-7]{52,})$/.test(cid);
} Try / catch
try {
await pub.pin(cid, name);
} catch (e) {
const msg = (e as Error).message;
if (/HTTP 400/.test(msg)) throw new Error(`CID "${cid}" is malformed or unknown to Pinata`);
if (/HTTP 409|already pinned/i.test(msg)) return; // idempotent success
throw e;
} Prevention
- Validate CID format before calling pin().
- Treat HTTP 409/duplicate as success if the CID is already pinned.
- Ensure the JWT has pinByHash/pinning scope.
- Confirm the CID is reachable on an IPFS gateway before asking Pinata to pin it.
When it happens
Trigger: HTTP 400 (malformed or invalid-length CID), 401/403 (JWT lacks pinning scope), 409 (already pinned — Pinata sometimes returns non-200 for duplicates), 429 (rate limit), or 5xx.
Common situations: Passing a CID with the wrong length or base; the CID exists on a gateway Pinata cannot reach; the JWT was scoped to uploads only; duplicate pin attempts during a retry loop.
Related errors
- Pinata upload failed (HTTP ${res.status}): ${JSON.stringify(
- Pinata list failed (HTTP ${res.status}): ${JSON.stringify(re
- Pinata JWT required (config.pinataJwt or PINATA_API_JWT)
- SSRF guard: private/loopback host rejected — ${host}
- SSRF guard: private/loopback host rejected — ${host}
AI-assisted analysis of ruvnet/ruflo@6b01dc5a68 (2026-08-12).
Data as JSON: /api/errors/508e584c6332167c.
Report an issue: GitHub.