paperclipai/paperclip · error

Environment event order mismatch.\nExpected

Error message

Environment event order mismatch.\nExpected: ${JSON.stringify(expectedOrder)}\nActual:   ${JSON.stringify(actual)}

What it means

Test-helper assertion in assertEnvironmentEventOrder: the recorded environment events, reduced to their type sequence, do not contain the expectedOrder subsequence (order-sensitive, allowing interleaved unrelated events). The error prints both the expected type list and the actual recorded order for diagnosing plugin lifecycle behavior in SDK harness tests.

Solutions

  1. Fix the environment lifecycle so events occur in the expected order; compare expected vs actual in the message.
Defensive patterns

Strategy: validation

When it happens

Trigger: Thrown at packages/plugins/sdk/src/testing.ts:259 when the library encounters an invalid state.

Common situations: See trigger scenarios.


AI-assisted analysis of paperclipai/paperclip@3f1d897a7c (2026-08-18). Data as JSON: /api/errors/65dae059ff879710. Report an issue: GitHub.

Appendix: source

Thrown at packages/plugins/sdk/src/testing.ts:260

  return events.filter((e) => e.type === type);
}

/** Assert that environment events occurred in the expected order. */
export function assertEnvironmentEventOrder(
  events: EnvironmentEventRecord[],
  expectedOrder: EnvironmentEventRecord["type"][],
): void {
  const actual = events.map((e) => e.type);
  const matched: EnvironmentEventRecord["type"][] = [];
  let cursor = 0;
  for (const eventType of actual) {
    if (cursor < expectedOrder.length && eventType === expectedOrder[cursor]) {
      matched.push(eventType);
      cursor++;
    }
  }
  if (matched.length !== expectedOrder.length) {
    throw new Error(
      `Environment event order mismatch.\nExpected: ${JSON.stringify(expectedOrder)}\nActual:   ${JSON.stringify(actual)}`,
    );
  }
}

/** Assert that a full lease lifecycle (acquire → release) occurred for an environment. */
export function assertLeaseLifecycle(
  events: EnvironmentEventRecord[],
  environmentId: string,
): { acquire: EnvironmentEventRecord; release: EnvironmentEventRecord } {
  const acquire = events.find((e) => e.type === "acquireLease" && e.environmentId === environmentId);
  const release = events.find((e) => (e.type === "releaseLease" || e.type === "destroyLease") && e.environmentId === environmentId);
  if (!acquire) throw new Error(`No acquireLease event found for environment ${environmentId}`);
  if (!release) throw new Error(`No releaseLease/destroyLease event found for environment ${environmentId}`);
  if (acquire.timestamp > release.timestamp) {
    throw new Error(`acquireLease occurred after release for environment ${environmentId}`);
  }
  return { acquire, release };

View on GitHub (pinned to 3f1d897a7c)