ruvnet/ruflo · error

Pinata JWT required (config.pinataJwt or PINATA_API_JWT)

Error message

Pinata JWT required (config.pinataJwt or PINATA_API_JWT)

What it means

RvfaPublisher needs a Pinata JWT for every API call. The constructor resolves it from config.pinataJwt then env PINATA_API_JWT and throws immediately if both are empty — a pure credentials-wiring error; no network request is attempted.

Solutions

  1. export PINATA_API_JWT=... (create one at pinata.cloud under API Keys)
  2. Or pass it explicitly: createPublisher({ pinataJwt: process.env.PINATA_API_JWT! })
  3. Construct the publisher after env/config loading completes, not at import time
  4. Fail fast at boot with a clear message when the credential is absent

Example fix

// before
const publisher = createPublisher(); // no config, no env → throws

// after
const pinataJwt = process.env.PINATA_API_JWT;
if (!pinataJwt) throw new Error('PINATA_API_JWT not set — create a key at pinata.cloud');
const publisher = createPublisher({ pinataJwt });
Defensive patterns

Strategy: validation

Validate before calling

const pinataJwt = process.env.PINATA_API_JWT;
if (!pinataJwt) {
  throw new Error('PINATA_API_JWT not set — create a key at pinata.cloud and export it');
}
const publisher = createPublisher({ pinataJwt });

Prevention

When it happens

Trigger: `new RvfaPublisher({})` or `createPublisher()` with PINATA_API_JWT unset; CI shells that never exported the variable; constructing the publisher at module load before .env is read; the JWT stored under a different variable name.

Common situations: Forgetting to source the env file; variable named PINATA_JWT or PINATA_KEY instead of PINATA_API_JWT; config object built before environment loading completes.

Related errors


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

Appendix: source

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

          { backupPath, newSize: newRvfa.length });
      }
    }

    return { success: true, backupPath, newSize: newRvfa.length, patchedSection: sec, errors: [] };
  }
}

// ── RvfaPublisher ────────────────────────────────────────────
export class RvfaPublisher {
  private jwt: string;
  private gw: string;
  private api: string;

  constructor(config: PublishConfig) {
    this.jwt = config.pinataJwt || process.env.PINATA_API_JWT || '';
    this.gw = (config.gatewayUrl || DEFAULT_GW).replace(/\/+$/, '');
    this.api = (config.apiUrl || DEFAULT_API).replace(/\/+$/, '');
    if (!this.jwt) throw new Error('Pinata JWT required (config.pinataJwt or PINATA_API_JWT)');
  }

  private async upload(
    fileName: string, data: Buffer, kv: Record<string, string>,
  ): Promise<PublishResult> {
    const meta = JSON.stringify({ name: fileName, keyvalues: kv });
    const { body, ct } = multipart('file', fileName, data, meta);
    const res = await pinataReq('POST', `${this.api}/pinning/pinFileToIPFS`, this.jwt, body, ct);
    if (res.status !== 200)
      throw new Error(`Pinata upload failed (HTTP ${res.status}): ${JSON.stringify(res.data)}`);
    const r = res.data as { IpfsHash: string; PinSize: number };
    return {
      cid: r.IpfsHash, size: r.PinSize,
      gatewayUrl: `${this.gw}/ipfs/${r.IpfsHash}`, pinataUrl: `${this.api}/pinning/pins/${r.IpfsHash}`,
    };
  }

  async publish(rvfaPath: string, meta?: PublishMetadata): Promise<PublishResult> {

View on GitHub (pinned to fa13ee4ad6)