[BUG] OpenRouter image generation fails (500) for models requiring the dedicated /images endpoint (e.g. bytedance-seed/seedream-5-0-pro)

Author: AbhinavPraveenCreated Aug 21, 2026Updated Sep 15, 2026
Labels🐛 Bug

Environment

Docker

System

Firefox + Podman

Version

1.18.0

Desktop Information

  • Generation API: OpenRouter
  • Model: bytedance-seed/seedream-5-0-pro

Describe the problem

TLDR, SillyTavern doesn't use OpenRouter's image generation API ( https://openrouter.ai/docs/guides/overview/multimodal/image-generation ) and I believe this breaks at least Seedream 5.0 Pro with SillyTavern + OpenRouter.

Generated by GitHub Copilot.

When generating an image using the OpenRouter model bytedance-seed/seedream-5-0-pro, the request fails with a 500 error. I expect the image to be generated successfully.

Steps to reproduce:

  1. Configure OpenRouter as the image generation source.
  2. Select the model bytedance-seed/seedream-5-0-pro.
  3. Enter a prompt (e.g. "Hello") and generate an image.

Actual result: Request fails with a 500 Internal Server Error. Expected result: Image is generated successfully.

Root cause: SillyTavern's /api/openrouter/image/generate route (in src/endpoints/openrouter.js) sends the request to OpenRouter's /chat/completions endpoint using the modalities: ['image'] + image_config pattern. However, this model requires OpenRouter's dedicated POST https://openrouter.ai/api/v1/images endpoint instead. Sending the request to /chat/completions causes OpenRouter to return an opaque 500 error rather than a clean error message.

I confirmed that sending the equivalent request directly to https://openrouter.ai/api/v1/images via curl succeeds:

bash
curl https://openrouter.ai/api/v1/images \
  -H "Authorization: Bearer $OPENROUTER_KEY" \
  --json '{"model":"bytedance-seed/seedream-5-0-pro","prompt":"Hello","aspect_ratio":"1:1"}'

The successful response places the generated image at data[0].b64_json, with the MIME type at data[0].media_type (e.g. "image/jpeg"), rather than the choices[0].message.images[0].image_url.url shape returned by /chat/completions.

Suggested fix:

  • Update the /image/generate route in src/endpoints/openrouter.js to send requests to ${API_OPENROUTER}/images with a body of { model, prompt, aspect_ratio } (instead of /chat/completions with messages + modalities + image_config).
  • Update the response parsing logic to read data[0].b64_json and data[0].media_type from the /images response, converting to the existing output shape { format, image } (using mime.extension(mediaType) for format and the base64 string for image), instead of parsing a data:...;base64,... URI from choices[0].message.images[0].image_url.url.
  • Consider whether any models still require the old /chat/completions + modalities: ['image'] pattern, and if so, support both paths (e.g. by trying /images first and falling back, or by using the existing fetchModelsByModality logic in the same file to determine which endpoint a given model needs).
  • Preserve existing error handling (status codes, warning logs) and keep the final response shape { format, image } unchanged so no frontend changes are required.

Additional info

Server console output when the bug occurs:

OpenRouter image generation request {
  model: 'bytedance-seed/seedream-5-0-pro',
  prompt: 'best quality, absurdres, masterpiece, "Hello"',
  aspect_ratio: '1:1'
}
OpenRouter image generation failed {"error":{"message":"Internal Server Error","code":500}}

Relevant current code (src/endpoints/openrouter.js):

javascript
router.post('/image/generate', async (req, res) => {
    try {
        const key = readSecret(req.user.directories, SECRET_KEYS.OPENROUTER);

        if (!key) {
            console.warn('OpenRouter API key not found');
            return res.status(400).json({ error: 'OpenRouter API key not found' });
        }

        console.debug('OpenRouter image generation request', req.body);

        const { model, prompt } = req.body;

        if (!model || !prompt) {
            return res.status(400).json({ error: 'Model and prompt are required' });
        }

        const response = await fetch(`${API_OPENROUTER}/chat/completions`, {
            method: 'POST',
            headers: {
                ...OPENROUTER_HEADERS,
                'Content-Type': 'application/json',
                'Authorization': `Bearer ${key}`,
            },
            body: JSON.stringify({
                model: model,
                messages: [
                    {
                        role: 'user',
                        content: prompt,
                    },
                ],
                modalities: ['image'],
                image_config: {
                    aspect_ratio: req.body.aspect_ratio || '1:1',
                },
            }),
        });

        if (!response.ok) {
            console.warn('OpenRouter image generation failed', await response.text());
            return res.sendStatus(500);
        }

        /** @type {any} */
        const data = await response.json();

        const imageUrl = data?.choices?.[0]?.message?.images?.[0]?.image_url?.url;

        if (!imageUrl) {
            console.warn('No image URL found in OpenRouter response', data);
            return res.sendStatus(500);
        }

        const [mimeType, base64Data] = /^data:(.*);base64,(.*)$/.exec(imageUrl)?.slice(1) || [];

        if (!mimeType || !base64Data) {
            console.warn('Invalid image data format', imageUrl);
            return res.sendStatus(500);
        }

        const result = {
            format: mime.extension(mimeType) || 'png',
            image: base64Data,
        };

        return res.json(result);
    } catch (error) {
        console.error(error);
        return res.sendStatus(500);
    }
});

Full file: https://github.com/SillyTavern/SillyTavern/blob/main/src/endpoints/openrouter.js

Please tick the boxes

  • I have explained the issue clearly, and I included all relevant info
  • I have checked that this issue hasn't already been raised
  • I have checked the docs important
  • I confirm that my issue is not related to third-party content, unofficial extension or patch. If in doubt, check with a new user account and with extensions disabled