paperclipai/paperclip · error
CreateOS does not yet support leases with a guaranteed…
Error message
CreateOS does not yet support leases with a guaranteed expiration deadline.
What it means
acquire() creates a CreateOS sandbox lease, but the provider cannot guarantee a hard expiration at a caller-requested time: sandboxes only enforce an idle timeout, and the plugin refuses to promise an expiry it cannot enforce. If the caller supplies requestedExpiresAt, acquire throws immediately instead of creating a lease that might outlive the deadline.
Solutions
- Call acquire without requestedExpiresAt and rely on the sandbox idle timeout / explicit lease release.
- Schedule your own release (plugin.release or delete sandbox) with a host-local timer if a soft deadline suffices.
- If a guaranteed expiry is a hard requirement, use a different sandbox provider that supports provider-side expiration deadlines.
Example fix
// before
await acquire({ companyId, environmentId, config, requestedExpiresAt: new Date(Date.now() + 3600_000) });
// after
await acquire({ companyId, environmentId, config }); // manage release yourself Defensive patterns
Strategy: validation
Validate before calling
if (params.requestedExpiresAt != null) {
throw new Error("createos leases cannot guarantee expiration; omit requestedExpiresAt");
} Try / catch
try {
lease = await acquire(params);
} catch (err) {
if (err.message.includes("guaranteed expiration")) {
lease = await acquire({ ...params, requestedExpiresAt: undefined });
} else throw err;
} Prevention
- Do not set requestedExpiresAt for CreateOS leases
- Implement your own release timer if a soft deadline is needed
- Choose a deadline-capable provider when hard expiry is mandatory
When it happens
Trigger: onEnvironmentProbe → acquire is called with params.requestedExpiresAt set (non-null), e.g. the orchestrator asks for a lease guaranteed to end at a specific timestamp.
Common situations: Budget or governance policies that require time-boxed leases; callers porting from providers that support deadline leases; scheduling code that always sets an expiry by default.
Understand the failure class
Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.
Related errors
- CreateOS execution requires a lease from this environment.
- CreateOS lease cleanup must finish before resume.
- CreateOS lease is closing or requires cleanup.
- CreateOS process creation could not be confirmed; destroy…
- CreateOS workspace requires a lease from this environment.
AI-assisted analysis of paperclipai/paperclip@3f1d897a7c (2026-09-18).
Data as JSON: /api/errors/b395ec6d9615847f.
Report an issue: GitHub.
Appendix: source
Thrown at packages/plugins/sandbox-providers/createos/src/plugin.ts:24
} from "@paperclipai/plugin-sdk";
import { CreateosApiError, CreateosClient, object } from "./client.js";
import { parseConfig, resolveApiKey } from "./config.js";
import { CreateosCleanupError, execute, shellQuote } from "./execute.js";
import { syncFiles } from "./file-sync.js";
const CWD = "/paperclip-workspace";
// The host excludes .paperclip-runtime from workspace export, so the lease
// marker never becomes a user repository file.
const MARKER = `${CWD}/.paperclip-runtime/.paperclip-createos-lease`;
function metadataMatches(params: PluginEnvironmentDriverBaseParams, metadata?: Record<string, unknown>): boolean {
return metadata?.provider === "createos" && metadata.companyId === params.companyId &&
metadata.environmentId === params.environmentId && metadata.apiUrl === parseConfig(params.config).apiUrl;
}
async function acquire(params: PluginEnvironmentAcquireLeaseParams): Promise<PluginEnvironmentLease> {
// An idle timeout or a host-local timer cannot supply a provider expiry.
if (params.requestedExpiresAt) throw new Error("CreateOS does not yet support leases with a guaranteed expiration deadline.");
const config = parseConfig(params.config);
const client = new CreateosClient(config);
const signal = AbortSignal.timeout(config.timeoutMs);
const sandbox = await client.createSandbox(signal);
try {
await client.transition(sandbox.id, "running", signal);
const data = await client.json(`/sandboxes/${sandbox.id}/exec`, "POST", {
cmd: "/bin/bash", args: ["-lc", `mkdir -p -- ${shellQuote(CWD)}`],
}, signal);
if (object(data.result).exit_code !== 0) throw new Error("CreateOS workspace preparation failed; the image must provide Bash.");
const marker = randomUUID();
await client.upload(sandbox.id, MARKER, marker, signal);
return {
providerLeaseId: sandbox.id,
metadata: {
provider: "createos", apiUrl: config.apiUrl,
companyId: params.companyId, environmentId: params.environmentId,
remoteCwd: CWD, shellCommand: "bash", marker,View on GitHub (pinned to 3f1d897a7c)