ruvnet/ruflo · error · Error

Invalid GCS bucket name: ${config.bucket}

Error message

Invalid GCS bucket name: ${config.bucket}

What it means

Before invoking `gcloud storage cp`, uploadToGCS validates config.bucket through isValidBucketName(), which enforces GCS bucket naming rules (lowercase letters, digits, hyphens/underscores, length limits, no 'goog' prefix, etc.). A value failing those rules — uppercase letters, spaces, a 'gs://' scheme accidentally included, or a malformed name — is rejected. Comment 'S-1' marks this as command-injection hardening, since the bucket is interpolated into a gcloud argument.

Source

Thrown at v3/@claude-flow/cli/src/transfer/storage/gcs.ts:130

      'GCS not configured. Set GCS_BUCKET environment variable.\n' +
      'Or authenticate: gcloud auth login && gcloud config set project YOUR_PROJECT'
    );
  }

  const contentId = generateContentId(content);
  const checksum = crypto.createHash('sha256').update(content).digest('hex');
  const fileName = options.name || `${contentId}.cfp.json`;

  // Validate filename to prevent path traversal
  if (!/^[a-zA-Z0-9._\-]+$/.test(fileName) || fileName.includes('..')) {
    throw new Error(`Invalid filename: ${fileName}`);
  }

  const objectPath = config.prefix ? `${config.prefix}/${fileName}` : fileName;

  // S-1: Validate bucket name and object path to prevent command injection
  if (!isValidBucketName(config.bucket)) {
    throw new Error(`Invalid GCS bucket name: ${config.bucket}`);
  }
  if (!isValidObjectPath(objectPath)) {
    throw new Error(`Invalid GCS object path: ${objectPath}`);
  }

  console.log(`[GCS] Uploading to gs://${config.bucket}/${objectPath}...`);

  // Write content to temp file
  const tempDir = process.env.TMPDIR || '/tmp';
  const tempFile = path.join(tempDir, `claude-flow-upload-${Date.now()}.json`);
  fs.writeFileSync(tempFile, content);

  try {
    // Build gcloud args (array form prevents shell injection)
    const uploadArgs = ['storage', 'cp', tempFile, `gs://${config.bucket}/${objectPath}`];
    if (config.projectId) uploadArgs.push(`--project=${config.projectId}`);
    uploadArgs.push(`--content-type=${options.contentType || 'application/json'}`);

View on GitHub (pinned to fa13ee4ad6)

Solutions

  1. Set GCS_BUCKET to the bare bucket name, lowercase, no scheme and no trailing slash — e.g. 'my-pattern-bucket' not 'gs://my-pattern-bucket/'
  2. Trim whitespace/newlines from the env value (common with .env files and shell exports)
  3. Rename to comply with GCS rules: 3-222 chars, lowercase letters/digits/hyphens/underscores, not starting with 'goog'
  4. Cross-check with `gcloud storage ls gs://<name>` that the name resolves before rerunning the upload

Example fix

# before
export GCS_BUCKET="gs://My-Bucket/" # scheme + uppercase -> Invalid GCS bucket name

# after
export GCS_BUCKET=my-bucket
npx claude-flow hooks transfer store --storage gcs
Defensive patterns

Strategy: validation

Validate before calling

function isValidBucketName(bucket: string): boolean {
  return /^[a-z0-9][a-z0-9_-]{1,219}[a-z0-9]$/.test(bucket)
    && !bucket.startsWith('goog');
}

const bucket = process.env.GCS_BUCKET!;
if (!isValidBucketName(bucket)) {
  throw new Error(`GCS_BUCKET '${bucket}' violates GCS naming rules (lowercase, no gs:// scheme, 3-222 chars)`);
}
await uploadToGCS(content, { config: { bucket } });

Prevention

When it happens

Trigger: Setting GCS_BUCKET='gs://my-bucket' (scheme included); uppercase or spaced bucket names like 'My Bucket'; trailing slashes; bucket names copied from URLs; values under 3 or over 222 characters.

Common situations: Pasting the bucket URI from the GCP console instead of the bare name; case mismatches (GCS buckets are globally lowercase-unique); whitespace from shell config or .env quoting; names with dots beyond allowed patterns.

Related errors


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