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
- export WEB3_STORAGE_TOKEN=<your token> (free token at https://web3.storage) and rerun
- Or pass the token programmatically via options.apiKey / the Web3StorageConfig option on the upload call
- Verify the variable reaches the process: print process.env.WEB3_STORAGE_TOKEN in the same context
- 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
- Add a preflight check at startup: fail configuration validation when a selected provider lacks its credentials
- Centralize provider selection so the process knows which env vars are required before the first upload
- Document required variables per provider (WEB3_STORAGE_TOKEN, PINATA_API_KEY/SECRET, IPFS_API_URL) in your runbook
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
- Pinata API credentials not found. Set PINATA_API_KEY and PIN
- Web3.storage upload failed: ${response.status} ${error}
- Pinata upload failed: ${response.status} ${error}
- Local IPFS upload failed: ${response.status} ${error}
- GCS not configured. Set GCS_BUCKET environment variable. Or
AI-assisted analysis of ruvnet/ruflo@fa13ee4ad6 (2026-08-18).
Data as JSON: /api/errors/825112e13f007e91.
Report an issue: GitHub.