OpenCode: skip cachePoint on Bedrock DocumentBlock messages (#17300)
SkillCommunicationOpenCode places cachePoint on Bedrock messages containing DocumentBlocks, which produces a "nothing available to cache" error.
Available today. Use it from your connected AI after setup.
No other account needed.
Connect ahel once, and every AI you use reads what you have installed.
Then ask your AI: use the OpenCode: skip cachePoint on Bedrock DocumentBlock messages (#17300) skill
What this skill tells your AI
The instructions your AI receives, as published by onlyterp/prompt-cache-skills in skills/opencode-bedrock-doc-blocks/SKILL.md and read by ahel’s review.
Target
packages/opencode/src/provider/transform.ts → applyCaching() in
sst/opencode.
Open issue: #17300 — "Bedrock prompt caching error: nothing available to cache".
Symptom
applyCaching() places cachePoint markers on the last 2 non-system
messages. If either of those messages contains a DocumentBlock
(PDF/file attachment that Bedrock processes server-side), the
cachePoint lands on content that Bedrock considers non-cacheable,
producing an API error:
ValidationException: nothing available to cache
The error fails the entire request, not just the caching attempt.
Fix
Add a DocumentBlock detector and skip cachePoint placement on
affected messages, falling through to the next-most-recent stable
non-document message:
--- a/packages/opencode/src/provider/transform.ts
+++ b/packages/opencode/src/provider/transform.ts
@@ function applyCaching(msgs, model)
+ function hasDocumentBlock(msg: ModelMessage): boolean {
+ if (!Array.isArray(msg.content)) return false;
+ return msg.content.some((b: any) =>
+ b?.type === "document" ||
+ b?.type === "file" ||
+ b?.documentBlock != null
+ );
+ }
+
+ function findLastStableNonDoc(msgs: ModelMessage[], skip: number): number {
+ for (let i = msgs.length - 1 - skip; i >= 0; i--) {
+ if (msgs[i].role !== "system" && !hasDocumentBlock(msgs[i])) {
+ return i;
+ }
+ }
+ return -1;
+ }
@@
- // Apply to last 2 non-system messages
- const nonSystemMsgs = msgs.filter(m => m.role !== "system").slice(-2)
- nonSystemMsgs.forEach(msg => {
- msg.providerOptions = { /* cachePoint etc. */ }
- })
+ // For Bedrock, skip DocumentBlock-containing messages — they
+ // can't be cached and produce a hard error.
+ const isBedrock = model.providerID.includes("bedrock");
+ if (isBedrock) {
+ const lastStable = findLastStableNonDoc(msgs, 0);
+ const prevStable = findLastStableNonDoc(msgs, msgs.length - 1 - lastStable + 1);
+ [lastStable, prevStable].forEach(idx => {
+ if (idx < 0) return;
+ msgs[idx].providerOptions = { bedrock: { cachePoint: { type: "default" } } };
+ });
+ } else {
+ // Existing behavior for non-Bedrock providers
+ const nonSystemMsgs = msgs.filter(m => m.role !== "system").slice(-2);
+ nonSystemMsgs.forEach(msg => {
+ msg.providerOptions = { /* cachePoint etc. */ };
+ });
+ }
Verify
- Configure OpenCode with a Bedrock Claude model.
- Attach a PDF or text document to a chat message.
- Send a follow-up prompt referencing the document.
- Before fix: Bedrock returns 400 ValidationException.
- After fix: request succeeds;
cachePointlands on the most recent non-document message; response showscacheReadInputTokenCount > 0on the second identical follow-up.
Background
Bedrock's cachePoint requires that the prefix it caches contains
cacheable content. DocumentBlocks are processed server-side and
don't count toward the cacheable token budget — placing a
cachePoint on a message where the only content is a document
produces the "nothing to cache" error.
The fix is to detect document-containing messages and route the breakpoint to the next-most-stable text-bearing message.
See docs/concepts/bedrock.md.
Full audit: audits/opencode.md.
Signals
- GitHub stars
- 114
- Forks
- 9
- Last commit
- Aug 2026
Advanced
- Catalog kind
- skill
- Gateway key
opencode-bedrock-doc-blocks- Source
- github.com/onlyterp/prompt-cache-skills