denoland/deno · error

pledge test permissions called before restoring previous ple

Error message

pledge test permissions called before restoring previous pledge

What it means

Panic in the op_pledge_test_permissions op (cli/ops/testing.rs) backing `deno test`. Identical logic to the bench variant: pledging swaps the worker's PermissionsContainer for the test's restricted set and stores the original under PermissionsHolder; a second pledge while one is already stored panics, enforcing a single active permission pledge per worker.

Source

Thrown at cli/ops/testing.rs:94

#[derive(Clone)]
pub struct TestIsolateHandle(pub v8::IsolateHandle);

#[derive(Clone)]
struct PermissionsHolder(Uuid, PermissionsContainer);

#[op2(stack_trace)]
#[serde]
pub fn op_pledge_test_permissions(
  state: &mut OpState,
  #[serde] args: ChildPermissionsArg,
) -> Result<Uuid, deno_runtime::deno_permissions::ChildPermissionError> {
  let token = Uuid::new_v4();
  let parent_permissions = state.borrow_mut::<PermissionsContainer>();
  let worker_permissions = parent_permissions.create_child_permissions(args)?;
  let parent_permissions = parent_permissions.clone();

  if state.try_take::<PermissionsHolder>().is_some() {
    panic!("pledge test permissions called before restoring previous pledge");
  }
  state.put::<PermissionsHolder>(PermissionsHolder(token, parent_permissions));

  // NOTE: This call overrides current permission set for the worker
  state.put::<PermissionsContainer>(worker_permissions);

  Ok(token)
}

#[op2]
pub fn op_restore_test_permissions(
  state: &mut OpState,
  #[serde] token: Uuid,
) -> Result<(), JsErrorBox> {
  match state.try_take::<PermissionsHolder>() {
    Some(permissions_holder) => {
      if token != permissions_holder.0 {
        panic!(

View on GitHub (pinned to 9ad36f7a2c)

Solutions

  1. Pair every pledge with its restore (finally) before pledging again in harness code
  2. Audit custom harness forks for unbalanced pledge/restore paths, including early-exit error paths
  3. Report a bug with a minimal repro if stock `deno test` hits it

Example fix

// before (harness pseudo-code)
const t1 = pledge(args);
const t2 = pledge(args);          // panics
// after
const t1 = pledge(args);
try { runTests(); } finally { restore(t1); }
const t2 = pledge(args);
Defensive patterns

Strategy: validation

Validate before calling

// guard the testing harness entrypoint against double pledges
const pledged = { active: false };
function safePledge(args) {
  if (pledged.active) throw new Error('restore the previous pledge first');
  const t = pledgeOp(args);
  pledged.active = true;
  return t;
}

Prevention

When it happens

Trigger: The internal test-harness op is invoked twice without an intervening op_restore_test_permissions — from modified cli/js harness code, custom runners built on internal ops, or a harness re-entry bug.

Common situations: Contributors changing Deno's testing bootstrap; userland code poking internal ops; edge cases like nested test-server startup double-pledging. Not reachable through normal Deno.test() usage.

Related errors


AI-assisted analysis of denoland/deno@9ad36f7a2c (2026-08-20). Data as JSON: /api/errors/1c819a76b76f0b24. Report an issue: GitHub.