{"record":{"id":"1176637ea3666f4b","repo":"expo/expo","slug":"unknown-encoding-label-normalized-normaliz","errorCode":null,"errorMessage":"Unknown encoding: ${label} (normalized: ${normalizedLabel})","messagePattern":"Unknown encoding: (.+?) \\(normalized: (.+?)\\)","errorType":"exception","errorClass":"RangeError","httpStatus":null,"severity":"error","filePath":"packages/expo/src/winter/TextDecoder.ts","lineNumber":24,"sourceCode":"  ignoreBOM: boolean;\n  fatal: boolean;\n  bomSeen: boolean;\n  pending: Uint8Array;\n  streaming: boolean;\n}\n\nfunction assertValidUTF8Label(label: unknown): void {\n  const normalizedLabel = String(label).trim().toLowerCase();\n  switch (normalizedLabel) {\n    case 'unicode-1-1-utf-8':\n    case 'unicode11utf8':\n    case 'unicode20utf8':\n    case 'utf-8':\n    case 'utf8':\n    case 'x-unicode20utf8':\n      return;\n    default:\n      throw new RangeError(`Unknown encoding: ${label} (normalized: ${normalizedLabel})`);\n  }\n}\n\nfunction normalizeBytes(input: ArrayBuffer | ArrayBufferView | undefined): Uint8Array {\n  if (input === undefined) {\n    return EMPTY_BYTES;\n  } else if (input instanceof Uint8Array) {\n    return input;\n  } else if (ArrayBuffer.isView(input)) {\n    return new Uint8Array(input.buffer, input.byteOffset, input.byteLength);\n  } else if (\n    (input[Symbol.toStringTag] as string) === 'ArrayBuffer' ||\n    (input[Symbol.toStringTag] as string) === 'SharedArrayBuffer'\n  ) {\n    return new Uint8Array(input as ArrayBuffer);\n  } else {\n    throw new TypeError('The input must be an ArrayBuffer or ArrayBufferView');\n  }","sourceCodeStart":6,"sourceCodeEnd":42,"githubUrl":"https://github.com/expo/expo/blob/da586c407bd53c4369a994e6ed5d6cf3340420f5/packages/expo/src/winter/TextDecoder.ts#L6-L42","documentation":"expo's TextDecoder polyfill intentionally supports only the UTF-8 family of labels (utf-8, utf8, unicode20utf8, x-unicode20utf8), matching the WHATWG encoding standard's must-support encoding. Any other label throws a RangeError with both the original and the normalized label included, mirroring the spec's RangeError for unknown encodings.","triggerScenarios":"`new TextDecoder('utf-16le')`, `new TextDecoder('iso-8859-1')`, `new TextDecoder('windows-1252')` - any label that does not normalize to a UTF-8 alias - on a platform using expo's TextDecoder (e.g. React Native runtimes without a native TextDecoder).","commonSituations":"Porting web code that decodes UTF-16 response bodies; libraries assuming Node's full-ICU decoder is present; labels taken verbatim from a server's charset header.","solutions":["Decode as UTF-8: `new TextDecoder('utf-8')` - convert the data to UTF-8 upstream if it is not already.","Transcode the bytes to UTF-8 before decoding (server-side or with a dedicated converter).","On hosts with a native full TextDecoder (browsers, Node), use globalThis.TextDecoder instead of the polyfill."],"exampleFix":"// before\nconst dec = new TextDecoder('utf-16le'); // RangeError: Unknown encoding\n\n// after\nconst dec = new TextDecoder('utf-8'); // only UTF-8 is supported","handlingStrategy":"validation","validationCode":"const UTF8_LABELS = new Set(['utf-8', 'utf8', 'unicode20utf8', 'x-unicode20utf8']);\n\nfunction isSupportedLabel(label: string): boolean {\n  return UTF8_LABELS.has(label.trim().toLowerCase().replace(/[-_]/g, '')); // rough normalize\n}\n\nif (!isSupportedLabel(label)) label = 'utf-8';","typeGuard":null,"tryCatchPattern":"try {\n  decoder = new TextDecoder(label);\n} catch (error) {\n  if (error instanceof RangeError && error.message.startsWith('Unknown encoding')) {\n    decoder = new TextDecoder('utf-8'); // fall back to UTF-8\n  } else throw error;\n}","preventionTips":["Standardize on UTF-8 end to end so the default constructor is all you need.","Transcode non-UTF-8 data upstream (server side) rather than at the decoder.","Use the host's native TextDecoder where full encoding support is required."],"tags":["textdecoder","encoding","utf-8","rangeerror","web-standards"],"backgroundTag":"unsupported-encoding","analyzedSha":"da586c407bd53c4369a994e6ed5d6cf3340420f5","analyzedAt":"2026-08-23T00:40:06.936Z","contentChangedAt":"2026-08-23T00:40:06.936Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}