Skip to main content

no-floating-wake-locks

Require WakeLockSentinel handles to be retained so they can be released.

Rule catalog ID: R016

Targeted pattern scopeโ€‹

This rule targets screen wake lock requests:

  • navigator.wakeLock.request(...)
  • window.navigator.wakeLock.request(...)
  • globalThis.navigator.wakeLock.request(...)

The rule reports wake lock requests whose resulting WakeLockSentinel is immediately discarded, including await expressions that do not store, return, or pass the sentinel to another owner.

What this rule reportsโ€‹

The rule reports:

  • standalone wake lock requests such as navigator.wakeLock.request("screen");
  • voided wake lock requests such as void navigator.wakeLock.request("screen");
  • awaited standalone requests such as await navigator.wakeLock.request("screen");

It intentionally allows promise chains and lifecycle-manager calls that receive the sentinel. The rule focuses on directly unowned wake lock handles.

Why this rule existsโ€‹

navigator.wakeLock.request() resolves to a WakeLockSentinel. The sentinel is the handle that can be released manually with release(), and applications usually need to retain it to update UI, react to release events, or release the wake lock during cleanup.

Incorrectโ€‹

navigator.wakeLock.request("screen");
void navigator.wakeLock.request("screen");
async function keepAwake() {
await navigator.wakeLock.request("screen");
}

Correctโ€‹

async function keepAwake() {
const sentinel = await navigator.wakeLock.request("screen");

await sentinel.release();
}
async function keepAwake() {
return navigator.wakeLock.request("screen");
}
async function keepAwake() {
registerWakeLock(await navigator.wakeLock.request("screen"));
}

Behavior and migration notesโ€‹

Store the sentinel in the owner that will call release(). For UI code, that is usually a component, route, or media/session controller. Applications should also consider listening for the sentinel's release event because user agents can release wake locks automatically.

This rule does not autofix. Choosing the owning lifecycle and release behavior is a semantic decision.

ESLint flat config exampleโ€‹

import runtimeCleanup from "eslint-plugin-runtime-cleanup";

export default [
runtimeCleanup.configs.recommended,
];

When not to use itโ€‹

Do not enable this rule for code where wake lock ownership is intentionally hidden inside an abstraction that the rule cannot see. Prefer wrapping navigator.wakeLock.request() in that abstraction and disabling the rule only inside the wrapper if needed.

Further readingโ€‹