{"record":{"id":"4144b665689eea8f","repo":"withastro/astro","slug":"configured-image-service-is-not-a-local-service","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/generic.ts","lineNumber":19,"sourceCode":"// @ts-expect-error\nimport { imageConfig } from 'astro:assets';\nimport { isRemotePath } from '@astrojs/internal-helpers/path';\nimport { isRemoteAllowed } from '@astrojs/internal-helpers/remote';\nimport * as mime from 'mrmime';\nimport type { APIRoute } from '../../types/public/common.js';\nimport { getConfiguredImageService } from '../internal.js';\nimport { etag } from '../utils/etag.js';\nimport { loadImage } from './loadImage.js';\n\n/**\n * Endpoint used in dev and SSR to serve optimized images by the base image services\n */\nexport const GET: APIRoute = async ({ request }) => {\n\ttry {\n\t\tconst imageService = await getConfiguredImageService();\n\n\t\tif (!('transform' in imageService)) {\n\t\t\tthrow new Error('Configured image service is not a local service');\n\t\t}\n\n\t\tconst url = new URL(request.url);\n\t\tconst transform = await imageService.parseURL(url, imageConfig);\n\n\t\tif (!transform?.src) {\n\t\t\tthrow new Error('Incorrect transform returned by `parseURL`');\n\t\t}\n\n\t\tlet inputBuffer: ArrayBuffer | undefined = undefined;\n\n\t\tconst isRemoteImage = isRemotePath(transform.src);\n\n\t\tif (isRemoteImage && isRemoteAllowed(transform.src, imageConfig) === false) {\n\t\t\treturn new Response('Forbidden', { status: 403 });\n\t\t}\n\n\t\tconst sourceUrl = new URL(transform.src, url.origin);","sourceCodeStart":1,"sourceCodeEnd":37,"githubUrl":"https://github.com/withastro/astro/blob/d081033d5fe8e8a68c4bbbad4af9d2deb9c74bca/packages/astro/src/assets/endpoint/generic.ts#L1-L37","documentation":"The dev/SSR image optimization endpoint (GET in generic.ts) calls getConfiguredImageService() and requires a LocalImageService (one exposing a transform method). External image services (CDN passthrough that only generate URLs) lack transform, so the endpoint cannot optimize and throws a plain Error.","triggerScenarios":"Hitting the _image optimization endpoint when image.service is configured as an external service (a CDN service that only returns URLs), or a custom service missing the transform method.","commonSituations":"Switched to an external/CDN image service but something still requests the local optimization endpoint; wrote a custom service that only implements parseURL/getURL without transform.","solutions":["Use a local service (e.g. @astrojs/sharp) if you rely on the built-in optimization endpoint.","If you use an external service, depend on its generated URLs instead of calling the local endpoint.","Ensure any custom service implements transform (extend baseService and add it)."],"exampleFix":"// before - astro.config.mjs\nimage: { service: entrypoint({ entrypoint: 'passthroughImageService' }) }\n// caller requests /_image?... -> throws\n// after - use a local service for optimization\nimage: { service: passthroughImageService },\n// or\nimage: { service: sharpImageService }","handlingStrategy":"validation","validationCode":"// At config load, ensure the image service is local when you use the optimization endpoint.\nimport { isLocalService } from 'astro/assets';\nconst svc = await getConfiguredImageService();\nif (!isLocalService(svc)) throw new Error('Optimization endpoint requires a local image service (e.g. sharp).');","typeGuard":"import type { ImageService, LocalImageService } from 'astro/assets';\nfunction isLocalImageService(s: ImageService | undefined): s is LocalImageService {\n  return !!s && 'transform' in s;\n}","tryCatchPattern":null,"preventionTips":["Use a local service (sharp) when you depend on the _image optimization endpoint.","For external/CDN services, consume generated URLs and avoid the local endpoint.","Make custom services implement transform."],"tags":["image","config","image-service"],"backgroundTag":null,"analyzedSha":"d081033d5fe8e8a68c4bbbad4af9d2deb9c74bca","analyzedAt":"2026-08-12T13:37:29.035Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}