[BUG] OpenRouter image generation fails (500) for models requiring the dedicated /images endpoint (e.g. bytedance-seed/seedream-5-0-pro)
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:
- Configure OpenRouter as the image generation source.
- Select the model
bytedance-seed/seedream-5-0-pro. - 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:
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/generateroute insrc/endpoints/openrouter.jsto send requests to${API_OPENROUTER}/imageswith a body of{ model, prompt, aspect_ratio }(instead of/chat/completionswithmessages+modalities+image_config). - Update the response parsing logic to read
data[0].b64_jsonanddata[0].media_typefrom the/imagesresponse, converting to the existing output shape{ format, image }(usingmime.extension(mediaType)forformatand the base64 string forimage), instead of parsing adata:...;base64,...URI fromchoices[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/imagesfirst and falling back, or by using the existingfetchModelsByModalitylogic 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):
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
- 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
Source: SillyTavern/SillyTavern