{"record":{"id":"2d736002cf6c47ac","repo":"BabylonJS/Babylon.js","slug":"failed-to-fetch-ktx2-file-data-response-st","errorCode":null,"errorMessage":"Failed to fetch KTX2 file \"${data}\": ${response.status} ${response.statusText}","messagePattern":"Failed to fetch KTX2 file \"(.+?)\": (.+?) (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/dev/core/src/Materials/Textures/rawTexture2DArray.functions.ts","lineNumber":141,"sourceCode":" *\r\n * The data is transcoded to uncompressed RGBA. Keeping the texture in its transcoded compressed form would\r\n * require compressedTexImage3D support in the engine raw texture path, which does not exist yet, so the\r\n * GPU cost here matches a plain RGBA array texture.\r\n *\r\n * Only the base mip level stored in the file is uploaded; when generateMipMaps is on, the remaining levels are\r\n * regenerated by the engine. Uploading the file's own mip chain needs per-mip array uploads, which WebGL's\r\n * updateRawTexture2DArray does not support today.\r\n * @param scene defines the hosting scene\r\n * @param data defines the url of the KTX2 file, or its already fetched content\r\n * @param options defines optional creation settings\r\n * @returns a promise resolved with the created RawTexture2DArray\r\n */\r\nexport async function CreateTexture2DArrayFromKTX2Async(scene: Scene, data: string | ArrayBufferView, options?: ICreateTexture2DArrayFromKTX2Options): Promise<RawTexture2DArray> {\r\n    let buffer: ArrayBufferView;\r\n    if (typeof data === \"string\") {\r\n        const response = await fetch(data);\r\n        if (!response.ok) {\r\n            throw new Error(`Failed to fetch KTX2 file \"${data}\": ${response.status} ${response.statusText}`);\r\n        }\r\n        buffer = new Uint8Array(await response.arrayBuffer());\r\n    } else {\r\n        buffer = data;\r\n    }\r\n\r\n    const { KhronosTextureContainer2 } = await import(\"../../Misc/khronosTextureContainer2\");\r\n\r\n    if (!KhronosTextureContainer2.IsValid(buffer)) {\r\n        throw new Error(\"The provided data is not a valid KTX2 file.\");\r\n    }\r\n\r\n    const container = new KhronosTextureContainer2(scene.getEngine());\r\n\r\n    // forceRGBA: the transcoded compressed formats cannot be uploaded to an array texture yet (see above).\r\n    const decodedData = await container._decodeAsync(buffer, { forceRGBA: true });\r\n\r\n    if (decodedData.errors) {\r","sourceCodeStart":123,"sourceCodeEnd":159,"githubUrl":"https://github.com/BabylonJS/Babylon.js/blob/0592b347b8a4ee0236089ea86a749cacfdb266d8/packages/dev/core/src/Materials/Textures/rawTexture2DArray.functions.ts#L123-L159","documentation":"CreateTexture2DArrayFromKTX2Async accepts either an ArrayBufferView or a URL string. When a string is passed it fetches the file and throws a descriptive Error if the HTTP response is not ok, embedding status code and status text.","triggerScenarios":"Passing a KTX2 URL that returns 404/403/500 — wrong path, asset not deployed, missing permission, or server error.","commonSituations":"Assets not copied to the build output, wrong bucket/CDN path, or tokens required for the KTX2 file (this fetch sends no auth headers).","solutions":["Verify the KTX2 URL returns 200 (curl -I)","Ensure the KTX2 asset is included in the build/deploy output","Serve the file from an accessible origin or pre-fetch with credentials and pass the ArrayBufferView instead of a string","Fall back to the ArrayBufferView overload when a URL cannot be authenticated"],"exampleFix":"// before\nconst tex = await CreateTexture2DArrayFromKTX2Async(scene, \"ktx2/layers.ktx2\");\n// after\nconst res = await fetch(\"ktx2/layers.ktx2\");\nif (!res.ok) throw new Error(`ktx2/layers.ktx2 unavailable: ${res.status}`);\nconst tex = await CreateTexture2DArrayFromKTX2Async(scene, new Uint8Array(await res.arrayBuffer()));","handlingStrategy":"retry","validationCode":"async function assertKtx2Fetchable(url: string): Promise<void> {\n  const res = await fetch(url, { method: \"HEAD\" });\n  if (!res.ok) throw new Error(`KTX2 ${url} not available: ${res.status}`);\n}","typeGuard":null,"tryCatchPattern":"try {\n  const tex = await CreateTexture2DArrayFromKTX2Async(scene, ktx2Url);\n} catch (e) {\n  if (e instanceof Error && e.message.startsWith(\"Failed to fetch KTX2\")) {\n    console.error(`KTX2 missing: ${ktx2Url}`);\n    return createFallbackArrayTexture(scene);\n  }\n  throw e;\n}","preventionTips":["Verify KTX2 deployment paths in CI","HEAD-check URLs before loading","Pre-fetch with credentials when the host requires auth and pass the buffer instead of the URL"],"tags":["network","fetch","ktx2","http-status"],"backgroundTag":"http-request-failed","analyzedSha":"0592b347b8a4ee0236089ea86a749cacfdb266d8","analyzedAt":"2026-08-30T15:11:20.442Z","schemaVersion":2},"datasetVersion":"2026-08-30T18:17:15.746Z"}