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
- 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.
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
- Always acquire/resume a lease before scheduling syncIn.
- Treat a lease with no providerLeaseId as 'no sandbox yet' in caller state machines.
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
- Daytona syncOut requires a provider lease ID.
- Daytona sandbox handle mismatch: handle ${sandbox.id} does n
- Daytona sandbox lease ${scope.providerLeaseId} is no longer
- sync operation ${label} path is not a confined absolute path
- sync operation ${label} path escapes its confinement root: $
AI-assisted analysis of paperclipai/paperclip@67001ec6eb (2026-08-12).
Data as JSON: /api/errors/5f294c6027438dc3.
Report an issue: GitHub.