{"record":{"id":"5f294c6027438dc3","repo":"paperclipai/paperclip","slug":"daytona-syncin-requires-a-provider-lease-id","errorCode":null,"errorMessage":"Daytona syncIn requires a provider lease ID.","messagePattern":"Daytona syncIn requires a provider lease ID\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/plugins/sandbox-providers/daytona/src/plugin.ts","lineNumber":2461,"sourceCode":"      }\n      return {\n        ...result,\n        metadata: { ...(result.metadata ?? {}), getDurationMs, cacheHit },\n      };\n    });\n  },\n\n  // Opt-in native inbound transfer. Defining this hook (with onEnvironmentSyncOut)\n  // makes the worker advertise `environmentSyncIn`/`environmentSyncOut`, so the\n  // host runner routes Daytona workspace/asset transfers through the SDK's batch\n  // `uploadFiles` (plus host-side tarballs for directories) instead of the\n  // base64-over-exec fallback. Providers that do not define these keep the\n  // byte-identical fallback.\n  async onEnvironmentSyncIn(\n    params: PluginEnvironmentSyncInParams,\n  ): Promise<PluginEnvironmentSyncResult> {\n    if (!params.lease.providerLeaseId) {\n      throw new Error(\"Daytona syncIn requires a provider lease ID.\");\n    }\n    const config = parseDriverConfig(params.config);\n    const remoteDir = resolveSyncRemoteDir(params.lease);\n    const timeoutSeconds = toTimeoutSeconds(config.timeoutMs);\n    const scope = {\n      driverKey: params.driverKey,\n      companyId: params.companyId,\n      environmentId: params.environmentId,\n      providerLeaseId: params.lease.providerLeaseId,\n      config,\n    };\n    // Collect the advisory read-write destinations for this scope. This records\n    // intent only; it does not change the transfer below.\n    sandboxHandleWritableDirs.recordWritableTargets(scope, params.operations);\n    return await withSandboxActivityGate(scope, async () => {\n      const sandbox = await getSandbox(scope, { bypassTeardownGate: true });\n      await ensureSandboxStarted(sandbox, timeoutSeconds);\n      const result = await performSyncIn({","sourceCodeStart":2443,"sourceCodeEnd":2479,"githubUrl":"https://github.com/paperclipai/paperclip/blob/67001ec6eb96ae601aa27bc91d9b2415d665334a/packages/plugins/sandbox-providers/daytona/src/plugin.ts#L2443-L2479","documentation":"Thrown by onEnvironmentSyncIn at the top of the hook when params.lease.providerLeaseId is falsy. Native inbound file transfer needs a live Daytona sandbox id to resolve the handle, ensureSandboxStarted, and uploadFiles; without a lease id there is no target sandbox, so the hook refuses before parsing config or entering the activity gate.","triggerScenarios":"Calling onEnvironmentSyncIn with a lease that has no providerLeaseId (e.g. a synthetic/empty lease, or a lease from a provider that does not allocate a sandbox id), or calling syncIn before acquireLease/resumeLease has returned a providerLeaseId.","commonSituations":"Pipeline ordering bug where syncIn runs before lease acquisition completes; a reusable-lease miss that returned an empty lease object; a caller reusing a stale lease whose sandbox was already destroyed.","solutions":["Acquire (or resume) a Daytona lease first and pass the returned providerLeaseId into syncIn's lease object.","Guard the caller: skip syncIn when lease.providerLeaseId is empty instead of invoking the hook.","If using reuseLease semantics, make sure the cached lease still carries a valid sandbox id before reissuing syncIn."],"exampleFix":"// before\nawait plugin.onEnvironmentSyncIn({\n  ...params,\n  lease: { providerLeaseId: null },\n});\n\n// after\nconst lease = await plugin.onEnvironmentAcquireLease(acquireParams);\nawait plugin.onEnvironmentSyncIn({\n  ...params,\n  lease: { providerLeaseId: lease.providerLeaseId },\n});","handlingStrategy":"validation","validationCode":"function assertLeaseForSync(lease: { providerLeaseId?: string | null }): string {\n  if (!lease.providerLeaseId) {\n    throw new Error('Cannot syncIn without a provider lease; acquire one first.');\n  }\n  return lease.providerLeaseId;\n}","typeGuard":"function hasProviderLease(\n  l: { providerLeaseId?: string | null },\n): l is { providerLeaseId: string } {\n  return typeof l.providerLeaseId === 'string' && l.providerLeaseId.length > 0;\n}","tryCatchPattern":"try {\n  await plugin.onEnvironmentSyncIn(params);\n} catch (err) {\n  if (err instanceof Error && /syncIn requires a provider lease ID/.test(err.message)) {\n    const lease = await plugin.onEnvironmentAcquireLease(acquireParams);\n    await plugin.onEnvironmentSyncIn({ ...params, lease });\n    return;\n  }\n  throw err;\n}","preventionTips":["Always acquire/resume a lease before scheduling syncIn.","Treat a lease with no providerLeaseId as 'no sandbox yet' in caller state machines."],"tags":["daytona","sync","lease","input-validation","sandbox"],"backgroundTag":null,"analyzedSha":"67001ec6eb96ae601aa27bc91d9b2415d665334a","analyzedAt":"2026-08-12T12:05:45.408Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}