{"record":{"id":"1e11e6cf99dc2415","repo":"paperclipai/paperclip","slug":"daytona-syncout-download-failed-for-entry-source","errorCode":null,"errorMessage":"Daytona syncOut download failed for ${entry.source}: ${response?.error ?? \"no response returned\"}","messagePattern":"Daytona syncOut download failed for (.+?): (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/plugins/sandbox-providers/daytona/src/file-sync.ts","lineNumber":856,"sourceCode":"\n  let responses: FileDownloadResponse[];\n  try {\n    // One batched bulk download for all file mappings, reading the snapshots.\n    responses = await sandbox.fs.downloadFiles(requests, timeoutSeconds);\n  } catch (error) {\n    await cleanup();\n    throw error;\n  }\n\n  // Per-file failures surface in `.error`, not a thrown batch — fail loud on any.\n  // Responses are keyed by the (snapshot) request source; report the original\n  // sourcePath in the surfaced error for a caller-meaningful message.\n  const bySource = new Map(responses.map((response) => [response.source, response]));\n  for (const entry of finalize) {\n    const response = bySource.get(entry.snapshot);\n    if (!response || response.error) {\n      await cleanup();\n      throw new Error(\n        `Daytona syncOut download failed for ${entry.source}: ${response?.error ?? \"no response returned\"}`,\n      );\n    }\n  }\n\n  let bytesTransferred = 0;\n  try {\n    for (const entry of finalize) {\n      // chmod the temp before the rename so the target never appears at a widened\n      // window; rename preserves the inode's mode.\n      if (typeof entry.mode === \"number\") {\n        await fs.chmod(entry.temp, entry.mode);\n      }\n      bytesTransferred += (await fs.stat(entry.temp)).size;\n      await fs.rename(entry.temp, entry.target);\n    }\n  } catch (error) {\n    await cleanup();","sourceCodeStart":838,"sourceCodeEnd":874,"githubUrl":"https://github.com/paperclipai/paperclip/blob/67001ec6eb96ae601aa27bc91d9b2415d665334a/packages/plugins/sandbox-providers/daytona/src/file-sync.ts#L838-L874","documentation":"Thrown during syncOut finalization when the Daytona fs.downloadFiles batch response for a file entry is missing or carries an `.error`. Per-file failures surface in `.error` rather than a thrown batch, so the loop fails loud on the first missing/errored response, reporting the original sourcePath.","triggerScenarios":"A syncOut download of individual files returns a responses array where, for some entry.snapshot, either no matching response exists or response.error is set. The temp file is cleaned up before throwing.","commonSituations":"The source file was deleted in the sandbox between snapshot and download; Daytona API transient error downloading a specific file; permission denied reading the file; network interruption; the snapshot key mismatch between request and response.","solutions":["Inspect entry.source and the response.error in the message to identify the failing file.","Ensure source files exist and are readable in the sandbox at download time (avoid concurrent sandbox mutations during syncOut).","Retry the syncOut operation for transient Daytona/network errors.","If a file is legitimately absent, exclude it from the sync mapping or ensure it is created before sync."],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  await syncOutFile(...);\n} catch (e) {\n  if (e instanceof Error && e.message.includes('syncOut download failed')) {\n    // verify source exists in sandbox; retry once for transient Daytona errors\n  }\n  throw e;\n}","preventionTips":["Avoid mutating the sandbox source tree concurrently with syncOut.","Ensure source files are readable at download time (permissions, existence).","Retry transient Daytona download failures with backoff."],"tags":["daytona","file-sync","syncout","download","network"],"backgroundTag":null,"analyzedSha":"67001ec6eb96ae601aa27bc91d9b2415d665334a","analyzedAt":"2026-08-12T12:05:45.408Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}