{"record":{"id":"ac96e1f1d8e83e52","repo":"ruvnet/ruflo","slug":"pinata-upload-failed-http-res-status-json","errorCode":null,"errorMessage":"Pinata upload failed (HTTP ${res.status}): ${JSON.stringify(res.data)}","messagePattern":"Pinata upload failed \\(HTTP (.+?)\\): (.+?)","errorType":"http","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"v3/@claude-flow/cli/src/appliance/rvfa-distribution.ts","lineNumber":344,"sourceCode":"  private jwt: string;\n  private gw: string;\n  private api: string;\n\n  constructor(config: PublishConfig) {\n    this.jwt = config.pinataJwt || process.env.PINATA_API_JWT || '';\n    this.gw = (config.gatewayUrl || DEFAULT_GW).replace(/\\/+$/, '');\n    this.api = (config.apiUrl || DEFAULT_API).replace(/\\/+$/, '');\n    if (!this.jwt) throw new Error('Pinata JWT required (config.pinataJwt or PINATA_API_JWT)');\n  }\n\n  private async upload(\n    fileName: string, data: Buffer, kv: Record<string, string>,\n  ): Promise<PublishResult> {\n    const meta = JSON.stringify({ name: fileName, keyvalues: kv });\n    const { body, ct } = multipart('file', fileName, data, meta);\n    const res = await pinataReq('POST', `${this.api}/pinning/pinFileToIPFS`, this.jwt, body, ct);\n    if (res.status !== 200)\n      throw new Error(`Pinata upload failed (HTTP ${res.status}): ${JSON.stringify(res.data)}`);\n    const r = res.data as { IpfsHash: string; PinSize: number };\n    return {\n      cid: r.IpfsHash, size: r.PinSize,\n      gatewayUrl: `${this.gw}/ipfs/${r.IpfsHash}`, pinataUrl: `${this.api}/pinning/pins/${r.IpfsHash}`,\n    };\n  }\n\n  async publish(rvfaPath: string, meta?: PublishMetadata): Promise<PublishResult> {\n    const data = await readFile(rvfaPath);\n    const name = meta?.name || rvfaPath.split('/').pop() || 'appliance.rvf';\n    return this.upload(name, data, {\n      type: 'rvfa-appliance', version: meta?.version || '',\n      profile: meta?.profile || '', description: meta?.description || '',\n    });\n  }\n\n  async publishPatch(patchBuf: Buffer, meta?: PublishMetadata): Promise<PublishResult> {\n    const name = meta?.name || `patch-${Date.now()}.rvfp`;","sourceCodeStart":326,"sourceCodeEnd":362,"githubUrl":"https://github.com/ruvnet/ruflo/blob/6b01dc5a687b26b3e218f796de45ec51f8fa9e8c/v3/@claude-flow/cli/src/appliance/rvfa-distribution.ts#L326-L362","documentation":"Thrown by RvfaPublisher.upload() when Pinata's POST /pinning/pinFileToIPFS returns a non-200 status. The error embeds both the HTTP status and the parsed response body (JSON or raw) so the caller can diagnose the upstream cause. Upload is the backing call for publish() and publishPatch().","triggerScenarios":"HTTP 401 (invalid/expired JWT), 403 (JWT lacks pinning scope), 413 (file exceeds Pinata plan size limit), 429 (rate limited), 5xx (Pinata outage), or 400 (malformed multipart body).","commonSituations":"JWT expired since the publisher was constructed; appliance file is larger than the Pinata plan's per-file cap; burst publishing trips the rate limiter; transient Pinata 5xx during a release window.","solutions":["Inspect the embedded status code and JSON body in the error message to identify the cause.","For 401/403: regenerate the JWT from the Pinata dashboard and ensure it has pinning permissions.","For 413: reduce appliance size (strip sections) or upgrade the Pinata plan.","For 429/5xx: retry with exponential backoff (the call is idempotent on distinct filenames)."],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"async function safePublish(pub: RvfaPublisher, path: string, meta?: PublishMetadata) {\n  const maxAttempts = 4;\n  for (let attempt = 1; attempt <= maxAttempts; attempt++) {\n    try {\n      return await pub.publish(path, meta);\n    } catch (e) {\n      const msg = (e as Error).message;\n      const transient = /HTTP 429|HTTP 5\\d\\d/.test(msg);\n      if (!transient || attempt === maxAttempts) throw e;\n      await new Promise(r => setTimeout(r, 500 * 2 ** attempt));\n    }\n  }\n  throw new Error('unreachable');\n}","preventionTips":["Inspect the embedded HTTP status code in the message before retrying — only retry 429/5xx.","Keep the JWT fresh; rotate before expiry to avoid 401 cascades.","Check appliance size against the Pinata plan's per-file limit before uploading.","Throttle concurrent publishes to avoid 429 rate limiting."],"tags":["pinata","ipfs","network","upload"],"backgroundTag":null,"analyzedSha":"6b01dc5a687b26b3e218f796de45ec51f8fa9e8c","analyzedAt":"2026-08-12T13:20:50.148Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}