{"record":{"id":"db30e01a2e995f3e","repo":"oven-sh/bun","slug":"scp-failed-source-username-hostname","errorCode":null,"errorMessage":"SCP failed: ${source} -> ${username}@${hostname}:${destination}","messagePattern":"SCP failed: (.+?) -> (.+?)@(.+?):(.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"scripts/machine.mjs","lineNumber":1000,"sourceCode":"    command.push(`${hostname}:${destination}`);\n  }\n\n  let cause;\n  for (let i = 0; i < retries; i++) {\n    const result = await spawn(command, { stdio: \"inherit\" });\n    const { exitCode, stderr } = result;\n    if (exitCode === 0) {\n      return;\n    }\n\n    cause = stderr.trim() || undefined;\n    if (/(bad configuration option)|(no such file or directory)/i.test(stderr)) {\n      break;\n    }\n    await new Promise(resolve => setTimeout(resolve, Math.pow(2, i) * 1000));\n  }\n\n  throw new Error(`SCP failed: ${source} -> ${username}@${hostname}:${destination}`, { cause });\n}\n\n/**\n * @param {string} passwordData\n * @param {string} privateKeyPath\n * @returns {string}\n */\nfunction decryptPassword(passwordData, privateKeyPath) {\n  const name = basename(privateKeyPath, extname(privateKeyPath));\n  const tmpPemPath = mkdtemp(\"pem-\", `${name}.pem`);\n  try {\n    copyFile(privateKeyPath, tmpPemPath, { mode: 0o600 });\n    spawnSyncSafe([\"ssh-keygen\", \"-p\", \"-m\", \"PEM\", \"-f\", tmpPemPath, \"-N\", \"\"]);\n    const { stdout } = spawnSyncSafe(\n      [\"openssl\", \"pkeyutl\", \"-decrypt\", \"-inkey\", tmpPemPath, \"-pkeyopt\", \"rsa_padding_mode:pkcs1\"],\n      {\n        stdin: Buffer.from(passwordData, \"base64\"),\n      },","sourceCodeStart":982,"sourceCodeEnd":1018,"githubUrl":"https://github.com/oven-sh/bun/blob/8c5296ac459e8252d3cd702f3fbcbb0c249d95d5/scripts/machine.mjs#L982-L1018","documentation":"A retried scp (exponential backoff 2^i seconds) to username@hostname:destination exited non-zero on every attempt; the loop breaks early when stderr matches 'bad configuration option' or 'no such file or directory' (ssh/scp config or binary problems), otherwise it exhausts retries and throws with cause = last stderr.","triggerScenarios":"Windows VM not yet accepting SSH after boot; wrong key or credentials; destination directory missing on the remote; an unsupported option in ~/.ssh/config; scp binary path problems on the local host.","commonSituations":"Provisioning racing VM readiness; typo'd destination path; updated OpenSSH where an old config option was removed; security groups blocking port 22.","solutions":["Inspect error.cause — it holds scp's trimmed stderr with the real reason","Test connectivity first: `ssh user@host true`","Fix or remove the offending ~/.ssh/config option if stderr mentions 'bad configuration option'","Create the destination directory on the remote before scp, or wait for SSH readiness and retry"],"exampleFix":"// before\nawait scpTo(source, destination, machine);\n\n// after\ntry {\n  await scpTo(source, destination, machine);\n} catch (err) {\n  console.error('scp stderr:', err.cause);\n  throw err;\n}","handlingStrategy":"retry","validationCode":"// Confirm SSH readiness before the first scp attempt\nawait $`ssh -o BatchMode=yes -o ConnectTimeout=10 ${username}@${hostname} true`;","typeGuard":null,"tryCatchPattern":"try {\n  await scpTo(source, destination, machine);\n} catch (error) {\n  const stderr = String(error.cause ?? '');\n  if (/bad configuration option|no such file or directory/i.test(stderr)) {\n    // local ssh/scp setup problem — fix ~/.ssh/config, do not retry\n    throw error;\n  }\n  // otherwise: VM not ready yet — wait and retry (scpTo already backs off)\n  throw error;\n}","preventionTips":["Wait for the SSH port/health check before copying files to a fresh VM","Keep ~/.ssh/config minimal on CI hosts — unsupported options break every scp","Always read error.cause; the thrown message alone has no reason"],"tags":["ssh","scp","network","provisioning"],"backgroundTag":null,"analyzedSha":"8c5296ac459e8252d3cd702f3fbcbb0c249d95d5","analyzedAt":"2026-08-16T08:01:58.794Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}