{"record":{"id":"b7db5ef6e873c861","repo":"gorhill/uBlock","slug":"failed-to-initialize-public-suffix-list","errorCode":null,"errorMessage":"Failed to initialize public suffix list.","messagePattern":"Failed to initialize public suffix list\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"platform/nodejs/index.js","lineNumber":268,"sourceCode":"    compileList(...args) {\n        return compileList(...args);\n    }\n\n    async serialize() {\n        const data = snfe.serialize();\n        return s14e.serialize(data, { compress: true });\n    }\n\n    async deserialize(serialized) {\n        const data = s14e.deserialize(serialized);\n        return snfe.unserialize(data);\n    }\n\n    static async create({ noPSL = false } = {}) {\n        const instance = new StaticNetFilteringEngine();\n\n        if ( noPSL !== true && !pslInit() ) {\n            throw new Error('Failed to initialize public suffix list.');\n        }\n\n        return instance;\n    }\n\n    static async release() {\n        if ( snfeProxyInstance === null ) { return; }\n        snfeProxyInstance = null;\n        await useLists([]);\n    }\n}\n\n/******************************************************************************/\n\n// rollup.js needs module.exports to be set back to the local exports object.\n// This is because some of the code (e.g. publicsuffixlist.js) sets\n// module.exports. Once all included files are written like ES modules, using\n// export statements, this should no longer be necessary.","sourceCodeStart":250,"sourceCodeEnd":286,"githubUrl":"https://github.com/gorhill/uBlock/blob/c68df492fd951bc3355fd0c6fec4afa8e2eae0aa/platform/nodejs/index.js#L250-L286","documentation":"StaticNetFilteringEngine.create() initializes the Public Suffix List unless you pass { noPSL: true } (index.js:267). pslInit() (index.js:87) first tries a serialized snapshot at build/publicsuffixlist.json, then falls back to the raw asset assets/thirdparties/publicsuffix.org/list/effective_tld_names.dat; if both are unavailable or empty it returns undefined and create() throws. The PSL is required so the engine can reason about domains and TLDs for network filtering.","triggerScenarios":"Calling create() (or create({})) when build/publicsuffixlist.json is absent AND the effective_tld_names.dat asset is missing or empty. Importing the module from a bundle that excluded the JSON/data files. Running from a source checkout before the build step generates build/publicsuffixlist.json.","commonSituations":"Bundling with webpack/rollup in a way that drops the package's build/ or assets/ directories; deploying only the JS without the PSL data; a truncated or corrupt effective_tld_names.dat file; fresh source checkout with `npm run build` not yet run.","solutions":["If you do not need PSL-based matching, create the engine with `{ noPSL: true }`.","Ensure build/publicsuffixlist.json is present by running the package's build step (e.g. `npm run build`) before calling create().","Supply your own PSL data by calling the exported pslInit(rawString) with a non-empty string BEFORE create(); pslInit parses and caches it (index.js:88-90).","Confirm that assets/thirdparties/publicsuffix.org/list/effective_tld_names.dat ships with your deployment."],"exampleFix":"// before\nconst engine = await StaticNetFilteringEngine.create(); // throws if PSL data missing\n\n// after (option A: opt out)\nconst engine = await StaticNetFilteringEngine.create({ noPSL: true });\n\n// after (option B: supply PSL yourself)\nimport { StaticNetFilteringEngine, pslInit } from 'uBlock'; // exported index.js:291-295\npslInit(myPslText);               // parsed & cached when non-empty\nconst engine = await StaticNetFilteringEngine.create();","handlingStrategy":"validation","validationCode":"import { existsSync } from 'fs';\nimport { resolve } from 'path';\n\n// Probe the two sources pslInit() tries (index.js:97 and index.js:109-112).\nconst snapshot = resolve(pkgRoot, 'build/publicsuffixlist.json');\nconst rawList = resolve(pkgRoot, 'assets/thirdparties/publicsuffix.org/list/effective_tld_names.dat');\nconst pslAvailable = existsSync(snapshot) || existsSync(rawList);\n\nconst engine = await StaticNetFilteringEngine.create(\n  pslAvailable ? {} : { noPSL: true }\n);","typeGuard":null,"tryCatchPattern":"let engine;\ntry {\n  engine = await StaticNetFilteringEngine.create();\n} catch (err) {\n  if (err && /public suffix list/i.test(err.message)) {\n    // Fall back to no-PSL mode only if you can tolerate reduced domain reasoning.\n    engine = await StaticNetFilteringEngine.create({ noPSL: true });\n  } else {\n    throw err;\n  }\n}","preventionTips":["If PSL-based domain logic is not needed, pass { noPSL: true } from the start.","Ship build/publicsuffixlist.json and the assets/ PSL data with your bundle.","Run the package's build step before importing from a source checkout.","For full control, call the exported pslInit(rawText) with your own PSL data before create()."],"tags":["psl","initialization","assets","nodejs"],"backgroundTag":null,"analyzedSha":"c68df492fd951bc3355fd0c6fec4afa8e2eae0aa","analyzedAt":"2026-08-12T23:57:11.071Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}