paperclipai/paperclip · error · Error

Daytona syncIn requires a provider lease ID.

Error message

Daytona syncIn requires a provider lease ID.

What it means

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.

Source

Thrown at packages/plugins/sandbox-providers/daytona/src/plugin.ts:2461

      }
      return {
        ...result,
        metadata: { ...(result.metadata ?? {}), getDurationMs, cacheHit },
      };
    });
  },

  // Opt-in native inbound transfer. Defining this hook (with onEnvironmentSyncOut)
  // makes the worker advertise `environmentSyncIn`/`environmentSyncOut`, so the
  // host runner routes Daytona workspace/asset transfers through the SDK's batch
  // `uploadFiles` (plus host-side tarballs for directories) instead of the
  // base64-over-exec fallback. Providers that do not define these keep the
  // byte-identical fallback.
  async onEnvironmentSyncIn(
    params: PluginEnvironmentSyncInParams,
  ): Promise<PluginEnvironmentSyncResult> {
    if (!params.lease.providerLeaseId) {
      throw new Error("Daytona syncIn requires a provider lease ID.");
    }
    const config = parseDriverConfig(params.config);
    const remoteDir = resolveSyncRemoteDir(params.lease);
    const timeoutSeconds = toTimeoutSeconds(config.timeoutMs);
    const scope = {
      driverKey: params.driverKey,
      companyId: params.companyId,
      environmentId: params.environmentId,
      providerLeaseId: params.lease.providerLeaseId,
      config,
    };
    // Collect the advisory read-write destinations for this scope. This records
    // intent only; it does not change the transfer below.
    sandboxHandleWritableDirs.recordWritableTargets(scope, params.operations);
    return await withSandboxActivityGate(scope, async () => {
      const sandbox = await getSandbox(scope, { bypassTeardownGate: true });
      await ensureSandboxStarted(sandbox, timeoutSeconds);
      const result = await performSyncIn({

View on GitHub (pinned to 67001ec6eb)

Solutions

  1. Acquire (or resume) a Daytona lease first and pass the returned providerLeaseId into syncIn's lease object.
  2. Guard the caller: skip syncIn when lease.providerLeaseId is empty instead of invoking the hook.
  3. If using reuseLease semantics, make sure the cached lease still carries a valid sandbox id before reissuing syncIn.

Example fix

// before
await plugin.onEnvironmentSyncIn({
  ...params,
  lease: { providerLeaseId: null },
});

// after
const lease = await plugin.onEnvironmentAcquireLease(acquireParams);
await plugin.onEnvironmentSyncIn({
  ...params,
  lease: { providerLeaseId: lease.providerLeaseId },
});
Defensive patterns

Strategy: validation

Validate before calling

function assertLeaseForSync(lease: { providerLeaseId?: string | null }): string {
  if (!lease.providerLeaseId) {
    throw new Error('Cannot syncIn without a provider lease; acquire one first.');
  }
  return lease.providerLeaseId;
}

Type guard

function hasProviderLease(
  l: { providerLeaseId?: string | null },
): l is { providerLeaseId: string } {
  return typeof l.providerLeaseId === 'string' && l.providerLeaseId.length > 0;
}

Try / catch

try {
  await plugin.onEnvironmentSyncIn(params);
} catch (err) {
  if (err instanceof Error && /syncIn requires a provider lease ID/.test(err.message)) {
    const lease = await plugin.onEnvironmentAcquireLease(acquireParams);
    await plugin.onEnvironmentSyncIn({ ...params, lease });
    return;
  }
  throw err;
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of paperclipai/paperclip@67001ec6eb (2026-08-12). Data as JSON: /api/errors/5f294c6027438dc3. Report an issue: GitHub.