can1357/oh-my-pi · error · AIError.ValidationError
cachedContent cannot be combined with request-level ${incomp
Error message
cachedContent cannot be combined with request-level ${incompatibleFields.join(", ")} What it means
Google's context caching API does not allow request-level systemInstruction, tools, or toolConfig alongside cachedContent (the cache already carries them). buildGoogleGenerateContentParams detects any of these set together with cachedContent and throws AIError.ValidationError listing the offending fields.
Source
Thrown at packages/ai/src/providers/google-shared.ts:891
if (options.signal.aborted) {
throw new AIError.AbortError("Request aborted");
}
config.abortSignal = options.signal;
}
if (options.cachedContent !== undefined) {
// Blank names are never valid resource references; anything else stays
// opaque so we do not invent format/model/project checks here.
if (options.cachedContent.trim().length === 0) {
throw new AIError.ValidationError("cachedContent must not be blank");
}
const incompatibleFields = [
config.systemInstruction !== undefined && "systemInstruction",
config.tools !== undefined && "tools",
config.toolConfig !== undefined && "toolConfig",
].filter((field): field is string => Boolean(field));
if (incompatibleFields.length > 0) {
throw new AIError.ValidationError(
`cachedContent cannot be combined with request-level ${incompatibleFields.join(", ")}`,
);
}
config.cachedContent = options.cachedContent;
}
return {
model: model.id,
contents,
config,
};
}
/**
* Drive the `streamGoogle` / `streamGoogleVertex` event flow: build the assistant message,
* push start/done/error events, run `consumeGoogleStream`, and translate thrown errors into
* the canonical `error` event shape.
*View on GitHub (pinned to 9690622007)
Solutions
- Remove the request-level systemInstruction/tools/toolConfig and rely on what was baked into the cache
- Create the cached context with the system instruction and tools you need, then send only messages + cachedContent
- Split your code path: separate cache-backed requests from regular requests
- If tools differ per request, do not use cachedContent for those calls
Example fix
// before
await streamGoogle(model, { system, tools, messages, cachedContent: cacheName });
// after
await streamGoogle(model, { messages, cachedContent: cacheName }); // system/tools live in the cache
// or for per-request tools: create a cache per toolset, or drop cachedContent Defensive patterns
Strategy: validation
Validate before calling
function assertCacheCompatible(params: { system?: unknown; tools?: unknown; toolConfig?: unknown; cachedContent?: string }) {
if (!params.cachedContent) return;
const conflicts = [
params.system !== undefined && "systemInstruction",
params.tools !== undefined && "tools",
params.toolConfig !== undefined && "toolConfig",
].filter(Boolean);
if (conflicts.length) throw new TypeError(`cachedContent cannot be combined with ${conflicts.join(", ")}`);
} Type guard
function isCacheOnlyRequest(p: { system?: unknown; tools?: unknown; cachedContent?: string }): p is { cachedContent: string } {
return p.cachedContent !== undefined && p.system === undefined && p.tools === undefined;
} Try / catch
try {
await streamGoogle(model, params);
} catch (err) {
if (err instanceof AIError.ValidationError && err.message.startsWith("cachedContent cannot be combined")) {
const { system, tools, toolConfig, ...rest } = params;
return await streamGoogle(model, rest); // let the cache supply system/tools
}
throw err;
} Prevention
- Structure your request builder so cache-backed requests take a distinct params shape without system/tools
- Create caches that already include the systemInstruction and tools each call needs
- Encode this constraint in your types (discriminated union: CacheRequest vs StandardRequest) so TS rejects the combination
- Document in your codebase that Google cachedContent is mutually exclusive with request-level config
When it happens
Trigger: Passing cachedContent plus systemInstruction, tools, or toolConfig in the same request options — e.g. standard agent params (with tools attached) reused for a cache-backed call.
Common situations: Reusing a general request builder that always attaches tools for cached-context calls; forgetting that the cached context was created with its own system instruction/tools; Google tool-caching tutorials that warn against duplicating config.
Related errors
- cachedContent must not be blank
- `context.tools` must be an array when present
- Tool "${toolCall.name}" not found
- Unknown tool${unknown.length === 1 ? "" : "s"} in --tools: $
- Host tool at index ${index} must provide a non-empty name
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/90874fa0e0316518.
Report an issue: GitHub.