{"record":{"id":"a57851afa4791fbf","repo":"gorhill/uBlock","slug":"only-a-single-instance-is-supported","errorCode":null,"errorMessage":"Only a single instance is supported.","messagePattern":"Only a single instance is supported\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"platform/nodejs/index.js","lineNumber":210,"sourceCode":"    await useLists.promise;\n    useLists.promise = null;\n\n    // Commit changes\n    snfe.freeze();\n    snfe.optimize();\n}\n\nuseLists.promise = null;\n\n/******************************************************************************/\n\nconst fctx = new FilteringContext();\nlet snfeProxyInstance = null;\n\nclass StaticNetFilteringEngine {\n    constructor() {\n        if ( snfeProxyInstance !== null ) {\n            throw new Error('Only a single instance is supported.');\n        }\n        snfeProxyInstance = this;\n    }\n\n    useLists(lists) {\n        return useLists(lists);\n    }\n\n    matchRequest(details) {\n        return snfe.matchRequest(fctx.fromDetails(details));\n    }\n\n    matchAndFetchModifiers(details, modifier) {\n        return snfe.matchAndFetchModifiers(fctx.fromDetails(details), modifier);\n    }\n\n    hasQuery(details) {\n        return snfe.hasQuery(details);","sourceCodeStart":192,"sourceCodeEnd":228,"githubUrl":"https://github.com/gorhill/uBlock/blob/c68df492fd951bc3355fd0c6fec4afa8e2eae0aa/platform/nodejs/index.js#L192-L228","documentation":"StaticNetFilteringEngine is a singleton-by-design proxy over the shared module-level snfe engine. The constructor captures the first instance into the module-level snfeProxyInstance (index.js:212); a subsequent `new StaticNetFilteringEngine()` finds it non-null and throws (index.js:209). The slot is cleared only by StaticNetFilteringEngine.release() (index.js:276), so only one engine can live in a process at a time.","triggerScenarios":"Calling StaticNetFilteringEngine.create() twice without release() in between (create calls the constructor at index.js:265). Directly invoking `new StaticNetFilteringEngine()` a second time. Hot-reloading the module in a long-lived process without releasing the prior instance first.","commonSituations":"Test suites that spin up a fresh engine per case without teardown; calling create() again after an earlier call threw, on the assumption the failed instance was never registered; serverless warm reuse where module state persists across invocations; recreating the engine instead of updating its lists.","solutions":["Reuse the single instance returned by the first create() and update lists via its useLists() method rather than recreating.","Call `await StaticNetFilteringEngine.release()` before creating a new instance; release nulls snfeProxyInstance and resets lists.","In test suites, create once in beforeAll and call release() in afterAll, never per-test without teardown.","If you truly need two independent engines in one process, isolate them in separate child processes or worker threads."],"exampleFix":"// before\nconst engine = await StaticNetFilteringEngine.create();\nconst engine2 = await StaticNetFilteringEngine.create(); // throws: single instance\n\n// after\nconst engine = await StaticNetFilteringEngine.create();\nawait engine.useLists(lists);                  // update in place\nawait StaticNetFilteringEngine.release();      // free the singleton\nconst fresh = await StaticNetFilteringEngine.create(); // now ok","handlingStrategy":"validation","validationCode":"// Cache and reuse the singleton; release() before creating a new one.\nlet engine = null;\nasync function getEngine() {\n  if (engine) return engine;\n  engine = await StaticNetFilteringEngine.create();\n  return engine;\n}\nasync function replaceEngine() {\n  await StaticNetFilteringEngine.release();   // clears snfeProxyInstance\n  engine = null;\n  return getEngine();\n}","typeGuard":null,"tryCatchPattern":"// If a second create() may race (e.g. warm serverless), catch and reuse/release.\nlet engine = null;\nasync function once(fn) {\n  if (engine) return engine;\n  try {\n    engine = await StaticNetFilteringEngine.create();\n    return engine;\n  } catch (err) {\n    if (err && /single instance/i.test(err.message)) {\n      await StaticNetFilteringEngine.release();\n      engine = await StaticNetFilteringEngine.create();\n      return engine;\n    }\n    throw err;\n  }\n}","preventionTips":["Create the engine once and reuse it; update lists via useLists() instead of recreating.","Always pair creation with StaticNetFilteringEngine.release() in teardown.","In tests, use beforeAll/afterAll rather than per-test creation without release.","Run genuinely independent engines in separate processes or worker threads."],"tags":["singleton","nodejs","lifecycle"],"backgroundTag":null,"analyzedSha":"c68df492fd951bc3355fd0c6fec4afa8e2eae0aa","analyzedAt":"2026-08-12T23:57:11.071Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}