{"record":{"id":"98623a8e15e07320","repo":"can1357/oh-my-pi","slug":"at-least-one-locale-is-required","errorCode":null,"errorMessage":"At least one locale is required","messagePattern":"At least one locale is required","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/utils/src/headers.ts","lineNumber":129,"sourceCode":"\t\tversion,\n\t\tuserAgent: makeUserAgent(candidate.browser, candidate.operatingSystem, version),\n\t};\n}\n\n/** Generates coherent modern desktop browser navigation headers. */\nexport class HeaderGenerator {\n\t#options: ResolvedOptions;\n\t#rng: () => number;\n\n\t/** Creates a generator with reusable constraints and an optionally injectable RNG. */\n\tconstructor(options: Partial<HeaderGeneratorOptions> = {}) {\n\t\tthis.#rng = options.rng ?? Math.random;\n\t\tthis.#options = { ...DEFAULT_OPTIONS, ...options };\n\t\tif (this.#options.devices.some(device => device !== \"desktop\") && this.#options.strict) {\n\t\t\tthrow new Error(\"Only desktop browser profiles are available\");\n\t\t}\n\t\tif (this.#options.locales.length === 0 && this.#options.strict) {\n\t\t\tthrow new Error(\"At least one locale is required\");\n\t\t}\n\t}\n\n\t/** Generates one header set, applying per-call constraints and request overrides. */\n\tgetHeaders(options: Partial<HeaderGeneratorOptions> = {}, overrides: Headers = {}): Headers {\n\t\tconst resolved = { ...this.#options, ...options };\n\t\tconst rng = options.rng ?? this.#rng;\n\t\tconst profile = makeProfile(resolved, rng);\n\t\tconst headers: Headers = {\n\t\t\taccept:\n\t\t\t\tprofile.browser === \"chrome\"\n\t\t\t\t\t? \"text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7\"\n\t\t\t\t\t: \"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\",\n\t\t\t\"user-agent\": profile.userAgent,\n\t\t\t\"accept-encoding\": profile.browser === \"safari\" ? \"gzip, deflate, br\" : \"gzip, deflate, br, zstd\",\n\t\t\t\"accept-language\": formatLocales(resolved.locales.length > 0 ? resolved.locales : DEFAULT_OPTIONS.locales),\n\t\t\t\"upgrade-insecure-requests\": \"1\",\n\t\t\t\"sec-fetch-dest\": \"document\",","sourceCodeStart":111,"sourceCodeEnd":147,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/utils/src/headers.ts#L111-L147","documentation":"In strict mode the constructor requires a non-empty locales array, because Accept-Language generation needs at least one locale. If options.locales resolves to [] (explicitly passed empty array, since defaults provide ['en-US','en']) and strict is true, the constructor throws this Error at construction time.","triggerScenarios":"new HeaderGenerator({ strict: true, locales: [] }); or merging options where locales is overwritten with an empty array from config/JSON input while strict is enabled.","commonSituations":"Empty locales field in a settings file; spreading user options over defaults where locales: [] was explicitly serialized and strict: true set for reproducibility.","solutions":["Provide at least one locale, e.g. locales: ['en-US']","Set strict: false — getHeaders then falls back to default ['en-US','en'] locales","Drop the locales option to use defaults"],"exampleFix":"// before\nnew HeaderGenerator({ strict: true, locales: [] });\n// after\nnew HeaderGenerator({ strict: true, locales: [\"en-US\"] });","handlingStrategy":"validation","validationCode":"const locales = options.locales ?? [\"en-US\", \"en\"];\nif (options.strict && locales.length === 0) {\n  throw new Error(\"locales must not be empty in strict mode\");\n}","typeGuard":"function hasLocale(locales: readonly string[] | undefined): boolean {\n  return Array.isArray(locales) && locales.length > 0;\n}","tryCatchPattern":"try {\n  return new HeaderGenerator(opts);\n} catch (err) {\n  if (err instanceof Error && err.message === \"At least one locale is required\") {\n    return new HeaderGenerator({ ...opts, locales: [\"en-US\"] });\n  }\n  throw err;\n}","preventionTips":["Never serialize locales: [] into strict configs","Drop the locales option instead of passing an empty array","Validate locale lists when loading from JSON/settings","Keep strict mode for fully-specified configurations only"],"tags":["headers","validation","strict-mode","configuration"],"backgroundTag":"empty-list-selection","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}