ruvnet/ruflo · error · Error

Pinata JWT required (config.pinataJwt or PINATA_API_JWT)

Error message

Pinata JWT required (config.pinataJwt or PINATA_API_JWT)

What it means

Thrown by the RvfaPublisher constructor when no Pinata JWT is available — neither in the passed PublishConfig.pinataJwt nor in the PINATA_API_JWT environment variable. The JWT is required as a Bearer token for every Pinata API call (upload, list, pin), so the publisher refuses to construct without it rather than failing on the first request.

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 6b01dc5a68)

Solutions

  1. Export PINATA_API_JWT in the environment before running the CLI: export PINATA_API_JWT=eyJ... (obtain from Pinata dashboard > Keys).
  2. Pass it explicitly: new RvfaPublisher({ pinataJwt: process.env.MY_JWT }).
  3. If using a .env file, ensure it is loaded (e.g. dotenv) before constructing the publisher.
  4. Confirm the JWT is a valid Pinata API JWT, not an API key + secret pair (v1 vs v2 auth).

Example fix

// before
const pub = createPublisher(); // throws if PINATA_API_JWT unset

// after
const pub = createPublisher({ pinataJwt: process.env.PINATA_API_JWT });
// or: export PINATA_API_JWT=eyJ... before running the process
Defensive patterns

Strategy: validation

Validate before calling

function resolvePinataJwt(config?: { pinataJwt?: string }): string | null {
  return config?.pinataJwt || process.env.PINATA_API_JWT || null;
}

const jwt = resolvePinataJwt();
if (!jwt) {
  throw new Error('Set PINATA_API_JWT env var or pass pinataJwt before constructing RvfaPublisher');
}

Try / catch

try {
  const pub = new RvfaPublisher(config);
} catch (e) {
  if (/Pinata JWT required/.test((e as Error).message)) {
    throw new Error('No Pinata JWT found. Obtain one at https://app.pinata.cloud/keys and export PINATA_API_JWT');
  }
  throw e;
}

Prevention

When it happens

Trigger: Constructing new RvfaPublisher({}) or createPublisher() without setting PINATA_API_JWT and without passing pinataJwt. Running in a CI/CD shell or container where the env var was not propagated, or calling createPublisher() in a fresh process.

Common situations: Local dev without the env var exported; deploy manifests that stripped secrets; the JWT was stored in a .env that was not loaded; a typo in the variable name (PINATA_JWT vs PINATA_API_JWT).

Related errors


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