{"record":{"id":"8e78cd51946b4f41","repo":"ruvnet/ruflo","slug":"gcs-upload-failed-error","errorCode":null,"errorMessage":"GCS upload failed: ${error}","messagePattern":"GCS upload failed: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"v3/@claude-flow/cli/src/transfer/storage/gcs.ts","lineNumber":191,"sourceCode":"\n    return {\n      success: true,\n      uri,\n      publicUrl,\n      size: content.length,\n      checksum,\n      contentId,\n    };\n  } catch (error) {\n    // Clean up temp file on error (validate path is within temp dir)\n    try {\n      const resolvedTemp = path.resolve(tempFile);\n      if (resolvedTemp.startsWith(path.resolve(tempDir))) {\n        fs.unlinkSync(tempFile);\n      }\n    } catch { /* ignore */ }\n\n    throw new Error(`GCS upload failed: ${error}`);\n  }\n}\n\n/**\n * Download content from Google Cloud Storage\n */\nexport async function downloadFromGCS(\n  uri: string,\n  config?: GCSConfig\n): Promise<Buffer | null> {\n  const cfg = config || getGCSConfig();\n\n  console.log(`[GCS] Downloading from ${uri}...`);\n\n  // Write to temp file first\n  const tempDir = process.env.TMPDIR || '/tmp';\n  const tempFile = path.join(tempDir, `claude-flow-download-${Date.now()}.json`);\n","sourceCodeStart":173,"sourceCodeEnd":209,"githubUrl":"https://github.com/ruvnet/ruflo/blob/fa13ee4ad60ac2090b1480656eb233521790d640/v3/@claude-flow/cli/src/transfer/storage/gcs.ts#L173-L209","documentation":"Thrown by uploadToGCS() in the pattern-transfer storage backend when the underlying `gcloud storage cp` subprocess (run via execFileSync) exits non-zero. The catch block unlinks the temp file and re-wraps the cause, so the message is an umbrella over every gcloud CLI failure: missing binary, expired credentials, nonexistent bucket, IAM denial, or network error. It only fires on the `cp` step; a failed metadata update is silently ignored because the upload itself succeeded.","triggerScenarios":"Calling uploadToGCS() (directly or via the publish/`hooks transfer` flow with the GCS backend) when: (1) the gcloud CLI is not installed (spawn ENOENT); (2) `gcloud auth login` was never run or the token expired; (3) GCS_BUCKET names a bucket that does not exist or the account lacks object-create permission; (4) config.projectId points at the wrong GCP project; (5) a transient network outage interrupts `gcloud storage cp`. Note: GCS_BUCKET being unset fails earlier with a distinct 'GCS not configured' error, so this message implies configuration was present but the upload operation itself failed.","commonSituations":"CI containers that never preinstalled the Cloud SDK; GCS_BUCKET exported on a laptop whose `gcloud config set project` was never set, so gcloud errors with 'No project found'; read-only service accounts; typo'd bucket names; corporate proxies blocking storage.googleapis.com.","solutions":["Run `gcloud --version` on the machine doing the upload; if it fails, install the Google Cloud CLI and reopen the shell so it is on PATH.","Authenticate and select a project: `gcloud auth login && gcloud config set project YOUR_PROJECT` (or set the project via the config used by uploadToGCS).","Verify bucket access: `gcloud storage ls gs://YOUR-BUCKET` — fix the GCS_BUCKET value or grant the identity roles/storage.objectCreator on the bucket.","Re-run the publish/transfer operation; if the failure is intermittent, wrap uploadToGCS in a retry with backoff."],"exampleFix":"// before\nGCS_BUCKET=typo-bucket npx claude-flow hooks transfer publish\n// → Error: GCS upload failed: Error: Command failed: gcloud storage cp ...\n\n// after (terminal)\ngcloud auth login\ngcloud config set project my-project\ngcloud storage ls gs://my-patterns-bucket   # proves credentials + bucket\nGCS_BUCKET=my-patterns-bucket npx claude-flow hooks transfer publish","handlingStrategy":"retry","validationCode":"import { execFileSync } from 'node:child_process';\nimport { isGCloudAuthenticated } from './gcs.js';\n\nfunction gcloudAvailable(): boolean {\n  try { execFileSync('gcloud', ['--version'], { stdio: 'pipe' }); return true; }\n  catch { return false; }\n}\n// call before uploading:\nif (!gcloudAvailable()) throw new Error('install the gcloud CLI first');\nif (!(await isGCloudAuthenticated())) throw new Error('run: gcloud auth login');","typeGuard":null,"tryCatchPattern":"try {\n  const result = await uploadToGCS(content, { name, config });\n} catch (err) {\n  const msg = err instanceof Error ? err.message : String(err);\n  if (!msg.startsWith('GCS upload failed:')) throw err;      // not our error\n  if (/ENOENT/.test(msg)) throw new Error('gcloud CLI not installed');\n  if (/No project|quota|Unauthorized|401|403/.test(msg)) throw new Error(`auth/bucket perms: ${msg}`);\n  await backoffRetry(() => uploadToGCS(content, { name, config }), 3); // transient network\n}","preventionTips":["Pre-flight gcloud --version and gcloud auth print-access-token in CI before any transfer command","Pin GCS_BUCKET/GCS_PROJECT in the environment and verify with `gcloud storage ls gs://$GCS_BUCKET` during setup","Treat metadata-update failures as non-fatal (the library already does) — only `cp` failures need handling","Add retry-with-backoff only for messages matching network symptoms; retrying auth failures just burns quota"],"tags":["gcs","gcloud","cloud-storage","upload","cli-subprocess","network"],"backgroundTag":"cloud-storage-upload-failed","analyzedSha":"fa13ee4ad60ac2090b1480656eb233521790d640","analyzedAt":"2026-08-18T21:34:22.708Z","schemaVersion":2},"datasetVersion":"2026-08-22T14:17:55.899Z"}