ruvnet/ruflo · error

Pinata list failed (HTTP )

Error message

Pinata list failed (HTTP ${res.status}): ${JSON.stringify(res.data)}

What it means

GET /data/pinList?status=pinned returned non-200; the message embeds the status code and response body. In practice dominated by 401 (expired or invalid JWT), with 429 rate-limiting and 5xx incidents as the transient cases. Only this list endpoint is involved — pinning/fetching can still work if the cause is request-rate.

Solutions

  1. 401 → regenerate the JWT and update PINATA_API_JWT
  2. 429 → slow the polling cadence and cache the result between calls
  3. Verify any apiUrl override is the correct Pinata base URL
  4. Check status.pinata.cloud for ongoing incidents when 5xx
Defensive patterns

Strategy: retry

Validate before calling

let cached: PublishedItem[] | null = null;
let lastList = 0;
async function listThrottled(p: RvfaPublisher): Promise<PublishedItem[]> {
  if (cached && Date.now() - lastList < 60_000) return cached; // avoid rate limits
  cached = await p.list();
  lastList = Date.now();
  return cached;
}

Try / catch

try {
  await publisher.list();
} catch (e) {
  const msg = String(e);
  if (/HTTP 401/.test(msg)) throw new Error('Pinata JWT expired — rotate PINATA_API_JWT');
  if (/HTTP (429|5\d\d)/.test(msg)) { /* backoff and retry once */ }
  else throw e;
}

Prevention

When it happens

Trigger: `publisher.list()` with a revoked or expired JWT; frequent polling of list() tripping rate limits; a custom apiUrl that is wrong or targets a deprecated Pinata API host.

Common situations: Same JWT lifecycle problems as upload failures; dashboards or scripts that poll pinList every few seconds; API base URL overrides that drift from https://api.pinata.cloud.

Related errors


AI-assisted analysis of ruvnet/ruflo@fa13ee4ad6 (2026-08-18). Data as JSON: /api/errors/8cd0df5ec09ba733. Report an issue: GitHub.

Appendix: source

Thrown at v3/@claude-flow/cli/src/appliance/rvfa-distribution.ts:377

  }

  async publishPatch(patchBuf: Buffer, meta?: PublishMetadata): Promise<PublishResult> {
    const name = meta?.name || `patch-${Date.now()}.rvfp`;
    return this.upload(name, patchBuf, {
      type: 'rvfp-patch', version: meta?.version || '', description: meta?.description || '',
    });
  }

  async fetch(cid: string, outputPath: string): Promise<void> {
    const data = await httpGet(`${this.gw}/ipfs/${cid}`);
    await mkdir(dirname(outputPath), { recursive: true });
    await writeFile(outputPath, data);
  }

  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 ──────────────────────────────────────

View on GitHub (pinned to fa13ee4ad6)