can1357/oh-my-pi · error · AIError.ValidationError
Cursor blob not found
Error message
Cursor blob not found
What it means
Cursor's AgentService protocol references prompt blobs by id; readCursorBlob looks the id up in the per-conversation in-memory blob store and throws ValidationError when nothing is stored under that hex key. The blob needed to reconstruct the request is missing, so the conversation cannot continue.
Solutions
- Start a new conversation/session so blobs are written to a fresh store before being referenced.
- Keep the conversation and its blob store alive in the same process for the conversation's duration; persist blobs externally if sessions must survive restarts.
- Verify the blob id key encoding matches (hex string of the Uint8Array) on both write and read.
- Ensure conversationId rotation logic copies blob store entries to the rotated id.
Example fix
null
Defensive patterns
Strategy: try-catch
Validate before calling
if (!conversationBlobStores.get(conversationId)?.has(Buffer.from(blobId).toString("hex"))) {
// blob missing — start a fresh conversation instead of continuing
} Type guard
null
Try / catch
try {
await streamCursor(model, ctx, { conversationId, ...options });
} catch (err) {
if (err instanceof AIError.ValidationError && err.message === "Cursor blob not found") {
// restart with a new conversationId (fresh blob store)
return streamCursor(model, ctx, { conversationId: crypto.randomUUID(), ...options });
}
throw err;
} Prevention
- Persist blobs alongside conversation state if sessions must survive restarts.
- Keep conversation lifetime tied to its in-process blob store.
- Copy blob entries when rotating conversation ids.
When it happens
Trigger: Reading a blob id that was never written to the store for the current conversation — e.g. continuing a conversation whose blob store was discarded (process restart), referencing a blob from a different conversationId, or a stale/rotated conversation id mapping to a fresh empty Map.
Common situations: Server restart wiping the in-memory conversationBlobStores while conversation ids persist; resuming a session across processes; a blob id serialized/mismatched (hex vs raw bytes) so lookup misses.
Related errors
- Cursor cannot continue history from a different model ( /…
- Invalid RPC message cursor
- stale_cursor
- A postfix required element cannot follow an optional or…
- a user-supplied replacement endpoint is required
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/82f0c8af2c500aac.
Report an issue: GitHub.
Appendix: source
Thrown at packages/ai/src/providers/cursor.ts:4564
if (output.usage.contextTokens !== usedTokens) {
output.usage.contextTokens = usedTokens;
}
}
function createBlobId(data: Uint8Array): Uint8Array {
return new Uint8Array(createHash("sha256").update(data).digest());
}
function storeCursorBlob(blobStore: Map<string, Uint8Array>, data: Uint8Array): Uint8Array {
const blobId = createBlobId(data);
blobStore.set(Buffer.from(blobId).toString("hex"), data);
return blobId;
}
function readCursorBlob(blobStore: Map<string, Uint8Array>, blobId: Uint8Array): Uint8Array {
const data = blobStore.get(Buffer.from(blobId).toString("hex"));
if (!data) {
throw new AIError.ValidationError("Cursor blob not found");
}
return data;
}
/**
* Cursor AgentService reconstructs the model prompt from `requestContext.rules`,
* not from the client-supplied `rootPromptMessagesJson` system blobs. Map each
* OMP system-prompt entry to a global CursorRule so always-apply rules survive
* that reconstruction.
*/
export function buildCursorRequestContextRules(systemPrompt: readonly string[] | undefined): CursorRule[] {
return normalizeSystemPrompts(systemPrompt).map((content, index) =>
create(CursorRuleSchema, {
fullPath: `/omp/system-prompt/${index}.mdc`,
content,
source: CursorRuleSource.USER,
type: create(CursorRuleTypeSchema, {
type: {View on GitHub (pinned to 9690622007)