ruvnet/ruflo · error · Error

Web3.storage token not found. Set WEB3_STORAGE_TOKEN environ

Error message

Web3.storage token not found. Set WEB3_STORAGE_TOKEN environment variable.
Get a free token at: https://web3.storage

What it means

The IPFS transfer layer's uploadToWeb3Storage() needs a bearer token: it takes options.apiKey or falls back to getWeb3StorageToken() (the WEB3_STORAGE_TOKEN env var). When both are absent it throws before any network activity, with the recovery steps embedded in the message. This is provider-selection configuration, not a network failure.

Source

Thrown at v3/@claude-flow/cli/src/transfer/ipfs/upload.ts:83

  let result = 'bafybei';
  for (let i = 0; i < 44; i++) {
    const byte = cidBytes[i % cidBytes.length] || 0;
    result += base32Chars[byte % 32];
  }
  return result;
}

/**
 * Upload to web3.storage (real IPFS)
 */
async function uploadToWeb3Storage(
  content: Buffer,
  options: IPFSUploadOptions & Web3StorageConfig
): Promise<IPFSUploadResult> {
  const token = options.apiKey || getWeb3StorageToken();

  if (!token) {
    throw new Error(
      'Web3.storage token not found. Set WEB3_STORAGE_TOKEN environment variable.\n' +
      'Get a free token at: https://web3.storage'
    );
  }

  const endpoint = options.endpoint || 'https://api.web3.storage';
  const name = options.name || 'pattern.cfp.json';

  console.log(`[IPFS] Uploading ${content.length} bytes to web3.storage...`);

  // Create FormData-like body for upload
  const boundary = '----WebKitFormBoundary' + crypto.randomBytes(16).toString('hex');
  const body = Buffer.concat([
    Buffer.from(`--${boundary}\r\n`),
    Buffer.from(`Content-Disposition: form-data; name="file"; filename="${name}"\r\n`),
    Buffer.from(`Content-Type: application/json\r\n\r\n`),
    content,
    Buffer.from(`\r\n--${boundary}--\r\n`),

View on GitHub (pinned to fa13ee4ad6)

Solutions

  1. export WEB3_STORAGE_TOKEN=<your token> (free token at https://web3.storage) and rerun
  2. Or pass the token programmatically via options.apiKey / the Web3StorageConfig option on the upload call
  3. Verify the variable reaches the process: print process.env.WEB3_STORAGE_TOKEN in the same context
  4. If you do not want web3.storage, pick another provider (pinata via PINATA_API_KEY/SECRET, or a local node via IPFS_API_URL)

Example fix

# before
npx claude-flow hooks transfer store --provider web3
# throws: Web3.storage token not found...

# after
export WEB3_STORAGE_TOKEN=eyJ... # from https://web3.storage
npx claude-flow hooks transfer store --provider web3
Defensive patterns

Strategy: validation

Validate before calling

const token = options.apiKey ?? process.env.WEB3_STORAGE_TOKEN;
if (!token) {
  throw new Error('web3.storage provider selected but no token configured (set WEB3_STORAGE_TOKEN)');
}
await uploadToIPFS(content, { provider: 'web3', ...options });

Prevention

When it happens

Trigger: Calling uploadToIPFS(content, { provider: 'web3' }) (or the CFP export path that selects web3.storage) without WEB3_STORAGE_TOKEN set and without options.apiKey; running in CI/shell where the env var is not exported to the process.

Common situations: Fresh clones that never configured IPFS transfer secrets; env vars set in .env but the process was started without loading them; switching providers from local/pinata to web3 without adding the new token; tokens defined only in one shell session.

Related errors


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