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/bench.rs) backing `deno bench`. The test harness 'pledges' (temporarily replaces) the worker's permission set and stores the original in OpState under PermissionsHolder. Pledging again while a previous pledge is still active finds the stored holder and panics, because only one nested permission swap is supported.
Source
Thrown at cli/ops/bench.rs:64
state.borrow::<ModuleSpecifier>().to_string()
}
#[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 {View on GitHub (pinned to 9ad36f7a2c)
Solutions
- Restore before pledging again: always pair each pledge with op_restore_test_permissions(token) in a finally block
- Review custom harness code that calls these ops and fix the call ordering
- If this fires from stock `deno bench` usage, report it as a Deno bug with a minimal reproduction
Example fix
// before (harness pseudo-code)
const t1 = pledge(args);
const t2 = pledge(args); // panics: previous pledge active
// after
const t1 = pledge(args);
try { runBench(); } finally { restore(t1); }
const t2 = pledge(args); Defensive patterns
Strategy: validation
Validate before calling
// wrap the internal ops so a second pledge is refused before it panics
const state = { pledged: false };
function safePledge(args) {
if (state.pledged) throw new Error('previous pledge not restored');
const token = Deno[Deno.internal].pledgeTestPermissions(args);
state.pledged = true;
return token;
} Prevention
- Maintain strict pledge/restore pairing in harness code, restoring in finally blocks
- Never call the pledge op from concurrent paths in one worker
When it happens
Trigger: Calling the internal pledge op twice without an intervening restore — in practice, a custom/forked test runner (or Deno's own harness code misordered) invoking op_pledge_test_permissions before op_restore_test_permissions completed.
Common situations: Contributors modifying cli/js bench/testing harness logic; user code reaching into internal ops via unstable internals; a race where one bench worker re-enters the harness entrypoint. Not reachable through normal Deno.bench() usage.
Related errors
- restore test permissions token does not match the stored tok
- pledge test permissions called before restoring previous ple
- restore test permissions token does not match the stored tok
- BenchContext::end() has already been invoked
- invalid doc test hashbang: {} ({reason})
AI-assisted analysis of denoland/deno@9ad36f7a2c (2026-08-20).
Data as JSON: /api/errors/dabfb0c34fdb2c8c.
Report an issue: GitHub.