{"record":{"id":"cf8df9c57707f344","repo":"withastro/astro","slug":"configured-image-service-is-not-a-local-service-cf8df9","errorCode":null,"errorMessage":"Configured image service is not a local service","messagePattern":"Configured image service is not a local service","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/astro/src/assets/endpoint/shared.ts","lineNumber":45,"sourceCode":"\t\t}\n\n\t\treturn Buffer.from(await res.arrayBuffer());\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\nexport const handleImageRequest = async ({\n\trequest,\n\tloadLocalImage,\n}: {\n\trequest: Request;\n\tloadLocalImage: (src: string, baseUrl: URL) => Promise<Buffer | undefined>;\n}) => {\n\tconst imageService = await getConfiguredImageService();\n\n\tif (!('transform' in imageService)) {\n\t\tthrow new Error('Configured image service is not a local service');\n\t}\n\n\tconst url = new URL(request.url);\n\tconst transform = await imageService.parseURL(url, imageConfig);\n\n\tif (!transform?.src) {\n\t\treturn new Response('Invalid request', { status: 400 });\n\t}\n\n\t// Reject requests that attempt to convert a non-SVG source to SVG output.\n\t// This mirrors the same guard in verifyOptions() that protects the <Image> component path.\n\tif (transform.format === 'svg') {\n\t\tconst sourceFormat = inferSourceFormat(transform.src);\n\t\tif (sourceFormat !== 'svg') {\n\t\t\treturn new Response('Cannot convert non-SVG source to SVG format', { status: 403 });\n\t\t}\n\t}\n","sourceCodeStart":27,"sourceCodeEnd":63,"githubUrl":"https://github.com/withastro/astro/blob/d081033d5fe8e8a68c4bbbad4af9d2deb9c74bca/packages/astro/src/assets/endpoint/shared.ts#L27-L63","documentation":"Same 'transform' guard as the generic dev endpoint, but in the shared handleImageRequest used across adapters/build paths. It calls getConfiguredImageService() and requires a LocalImageService; an external service (no transform) throws a plain Error.","triggerScenarios":"An adapter or build/hybrid path that routes image requests through handleImageRequest while an external image service is configured.","commonSituations":"SSR adapter + external service where the shared handler is invoked; build-time optimization expecting a local service; custom service missing transform.","solutions":["Configure a local service (e.g. sharp) for paths that go through handleImageRequest.","For external/CDN services, rely on URL generation and avoid the local optimization handler.","Ensure a custom service implements transform."],"exampleFix":"// before - external service for an SSR build that hits the shared handler\nimage: { service: passthroughImageService }\n// after\nimage: { service: sharpImageService }","handlingStrategy":"validation","validationCode":"// Before relying on handleImageRequest, confirm the configured service is local.\nimport { isLocalService } from 'astro/assets';\nconst svc = await getConfiguredImageService();\nif (!isLocalService(svc)) throw new Error('Shared image handler requires a local service.');","typeGuard":"function isLocalImageService(s: any): boolean {\n  return s && typeof s === 'object' && typeof s.transform === 'function';\n}","tryCatchPattern":null,"preventionTips":["Configure a local service (sharp) for SSR/build paths using handleImageRequest.","Use external services only for URL generation, not local optimization.","Implement transform in any custom service."],"tags":["image","config","image-service","ssr"],"backgroundTag":null,"analyzedSha":"d081033d5fe8e8a68c4bbbad4af9d2deb9c74bca","analyzedAt":"2026-08-12T13:37:29.035Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}