nexu-io/open-design · error · Error
no Nano Banana API key — configure it in Settings or set OD_
Error message
no Nano Banana API key — configure it in Settings or set OD_NANOBANANA_API_KEY
What it means
Thrown by renderNanoBananaImage (Google Gemini 'Nano Banana' / gemini-2.5-flash-image provider) before any network call when credentials.apiKey is empty. It is the contract guard ensuring a key is present so the request can be authorized against the v1beta generateContent endpoint.
Source
Thrown at apps/daemon/src/media/index.ts:1673
} else {
throw new Error('grok image response missing b64_json/url');
}
// xAI's Imagine returns JPEG by default (no format option in the API
// surface), but PNG/WebP are technically possible. Sniff the magic
// bytes so the on-disk extension matches reality — saving JPEG bytes
// as `.png` confuses Finder previews and any downstream consumer that
// trusts the extension.
return {
bytes,
providerNote: `grok/${ctx.wireModel} · ${aspectRatio} · ${bytes.length} bytes`,
suggestedExt: sniffImageExt(bytes),
};
}
async function renderNanoBananaImage(ctx: MediaContext, credentials: ProviderConfig): Promise<RenderResult> {
const apiKey = credentials.apiKey;
if (!apiKey) {
throw new Error(
'no Nano Banana API key — configure it in Settings or set OD_NANOBANANA_API_KEY',
);
}
const baseUrl = (credentials.baseUrl || NANOBANANA_DEFAULT_BASE_URL).replace(/\/$/, '');
const wireModel = (credentials.model || ctx.wireModel || NANOBANANA_DEFAULT_MODEL).trim();
const body = {
contents: [{
parts: [{
text: ctx.prompt || 'A high-quality reference image.',
}],
}],
generationConfig: {
responseModalities: ['IMAGE'],
imageConfig: {
aspectRatio: nanoBananaAspectFor(ctx.aspect),
imageSize: NANOBANANA_DEFAULT_IMAGE_SIZE,
},View on GitHub (pinned to 5be4028344)
Solutions
- Open Settings in the web UI and paste the Nano Banana / Google AI Studio API key into the provider config.
- Or export OD_NANOBANANA_API_KEY in the daemon process environment and restart.
- If the key was set but the error persists, verify credentials.apiKey is actually loaded by the provider credentials loader (check the media provider registry).
Example fix
// before
const apiKey = credentials.apiKey;
if (!apiKey) {
throw new Error('no Nano Banana API key — configure it in Settings or set OD_NANOBANANA_API_KEY');
}
// after — fall back to env at the call site so headless setups work without UI
const apiKey = credentials.apiKey || process.env.OD_NANOBANANA_API_KEY;
if (!apiKey) {
throw new Error('no Nano Banana API key — configure it in Settings or set OD_NANOBANANA_API_KEY');
} Defensive patterns
Strategy: validation
Validate before calling
// Pre-flight check before invoking renderNanoBananaImage
function hasNanoBananaCredentials(creds: ProviderConfig): boolean {
return Boolean(creds.apiKey && creds.apiKey.trim());
}
// at the call site, before dispatching:
if (ctx.providerId === 'nanobanana' && !hasNanoBananaCredentials(credentials)) {
return { kind: 'config-error', message: 'Add your Nano Banana API key in Settings or set OD_NANOBANANA_API_KEY.' };
} Type guard
function nanoBananaConfigured(creds: ProviderConfig, env = process.env): boolean {
return Boolean((creds.apiKey && creds.apiKey.trim()) || env.OD_NANOBANANA_API_KEY);
} Try / catch
// caller wraps the dispatch
try {
await renderNanoBananaImage(ctx, credentials);
} catch (e) {
if (/no Nano Banana API key/.test(String(e))) {
return presentConfigPrompt('nanobanana');
}
throw e;
} Prevention
- Run a credential pre-flight in the provider registry before dispatching to renderNanoBananaImage.
- Allow OD_NANOBANANA_API_KEY as an env fallback at the call site so headless setups work.
- Surface a Settings deep-link in the UI when the key is missing rather than a raw stack error.
- Re-validate credentials after any config import/migration.
When it happens
Trigger: User selects the Nano Banana provider in Settings without entering an API key, OD_NANOBANANA_API_KEY env var is unset, or the credentials store failed to persist the key. The error message names both remediation paths explicitly.
Common situations: First-time provider setup where the user picked the model but skipped the key field; deploying the daemon in a fresh environment without exporting OD_NANOBANANA_API_KEY; key cleared by a settings reset.
Related errors
- nano-banana image ${resp.status}: ${truncate(text, 240)}
- nano-banana image non-JSON: ${truncate(text, 200)}
- nano-banana image response missing candidates[].content.part
- no OpenRouter API key — configure it in Settings or set OPEN
- openrouter image ${resp.status}: ${truncate(text, 240)}
AI-assisted analysis of nexu-io/open-design@5be4028344 (2026-08-12).
Data as JSON: /api/errors/d654bf235215d748.
Report an issue: GitHub.