paperclipai/paperclip · error · Error

Daytona template deletion requires @daytonaio/sdk snapshot.g

Error message

Daytona template deletion requires @daytonaio/sdk snapshot.get/delete support.

What it means

Thrown by onEnvironmentDeleteTemplate after the templateKind guard passes. The plugin casts the Daytona client to expose an optional snapshot service and requires both client.snapshot.get and client.snapshot.delete to be functions before deleting. It fires when the installed @daytonaio/sdk does not ship the snapshot service (or shipped it under a different shape), so deletion cannot be performed safely.

Source

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

      };
    } finally {
      sandboxHandleTeardownGates.end(scope, teardownGate);
      evictSandboxHandle(scope);
    }
  },

  async onEnvironmentDeleteTemplate(
    params: PluginEnvironmentDeleteTemplateParams,
  ): Promise<PluginEnvironmentDeleteTemplateResult> {
    const templateKind = params.templateKind ?? "snapshot";
    if (templateKind !== "snapshot") {
      throw new Error(`Daytona can delete snapshot templates only, not ${templateKind}.`);
    }
    const config = parseDriverConfig(params.config);
    const client = createDaytonaClient(config) as Daytona & { snapshot?: DaytonaSnapshotService };
    const snapshotService = client.snapshot;
    if (typeof snapshotService?.get !== "function" || typeof snapshotService.delete !== "function") {
      throw new Error("Daytona template deletion requires @daytonaio/sdk snapshot.get/delete support.");
    }
    const snapshot = await snapshotService.get(params.templateRef);
    await snapshotService.delete(snapshot);
    return {
      deleted: true,
      metadata: {
        provider: "daytona",
        templateKind: "snapshot",
        templateRefRedacted: true,
        reason: params.reason ?? null,
      },
    };
  },

  async onEnvironmentExecute(
    params: PluginEnvironmentExecuteParams,
  ): Promise<PluginEnvironmentExecuteResult> {
    if (!params.lease.providerLeaseId) {

View on GitHub (pinned to 67001ec6eb)

Solutions

  1. Upgrade @daytonaio/sdk to a version that exposes client.snapshot.get and client.snapshot.delete (the repo pins 0.203.0); rebuild the provider.
  2. In tests, stub client.snapshot with both get and delete as vi.fn() before invoking delete-template.
  3. If the SDK removed/renamed the service, update the DaytonaSnapshotService type at plugin.ts:147 and the cast at plugin.ts:2347 to match the new surface.

Example fix

// before (test mock)
const client = { snapshot: {} };

// after
const client = {
  snapshot: { get: vi.fn(), delete: vi.fn() },
};
Defensive patterns

Strategy: type-guard

Validate before calling

function snapshotDeletionSupported(client: unknown): boolean {
  const s = (client as { snapshot?: { get?: unknown; delete?: unknown } }).snapshot;
  return typeof s?.get === 'function' && typeof s?.delete === 'function';
}
// if (!snapshotDeletionSupported(client)) skip delete-template for this SDK.

Type guard

type SnapshotService = {
  get: (name: string) => Promise<unknown>;
  delete: (snapshot: unknown) => Promise<void>;
};
function hasSnapshotService(
  c: unknown,
): c is { snapshot: SnapshotService } {
  const s = (c as { snapshot?: Partial<SnapshotService> }).snapshot;
  return !!s && typeof s.get === 'function' && typeof s.delete === 'function';
}

Try / catch

try {
  await plugin.onEnvironmentDeleteTemplate(params);
} catch (err) {
  if (err instanceof Error && /snapshot\.get\/delete support/.test(err.message)) {
    // SDK cannot delete; leave the snapshot or fall back to manual cleanup
    return { deleted: false };
  }
  throw err;
}

Prevention

When it happens

Trigger: Calling delete-template on a Daytona SDK version whose client has no snapshot service, or where snapshot.get / snapshot.delete are not functions; this is the delete-side analogue of the capture-side _experimental_createSnapshot capability check.

Common situations: SDK downgrade below the version that introduced the snapshot service; a custom/forked SDK build that omits the snapshot service; running delete-template in a test harness with a mock client that only stubs create.

Related errors


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