{"record":{"id":"698a5bae784fbfbc","repo":"can1357/oh-my-pi","slug":"gemini-files-api-cannot-delete-a-handle-from-anoth","errorCode":null,"errorMessage":"Gemini Files API cannot delete a handle from another provider","messagePattern":"Gemini Files API cannot delete a handle from another provider","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/blob-broker/provider-files-gemini.ts","lineNumber":155,"sourceCode":"\n\t\t\tconst file = parseFinalizedFile(await responseJson(finalizeResponse, \"finalize\"));\n\t\t\treturn {\n\t\t\t\tprovider: \"google\",\n\t\t\t\tid: file.name,\n\t\t\t\turi: file.uri,\n\t\t\t\tmimeType: file.mimeType,\n\t\t\t\tbytes: byteLength,\n\t\t\t\texpiresAt: file.expiresAt,\n\t\t\t\tdelete: {\n\t\t\t\t\tmethod: \"DELETE\",\n\t\t\t\t\turl: `${GEMINI_FILES_RESOURCE_URL}/${file.name}`,\n\t\t\t\t\theaders: { \"x-goog-api-key\": credential },\n\t\t\t\t},\n\t\t\t};\n\t\t},\n\t\tasync delete(handle: ProviderFileHandle): Promise<void> {\n\t\t\tif (handle.provider !== \"google\")\n\t\t\t\tthrow new Error(\"Gemini Files API cannot delete a handle from another provider\");\n\t\t\tconst name = handle.id;\n\t\t\tif (typeof name !== \"string\" || !/^files\\/[^/]+$/.test(name)) {\n\t\t\t\tthrow new Error(\"Gemini Files API delete requires a valid file name\");\n\t\t\t}\n\t\t\tlet response: Response;\n\t\t\ttry {\n\t\t\t\tresponse = await fetchImpl(`${GEMINI_FILES_RESOURCE_URL}/${name}`, {\n\t\t\t\t\tmethod: \"DELETE\",\n\t\t\t\t\theaders: { \"x-goog-api-key\": credential },\n\t\t\t\t});\n\t\t\t} catch {\n\t\t\t\tthrow new Error(\"Gemini Files API delete request failed\");\n\t\t\t}\n\t\t\tif (!response.ok) throw new Error(`Gemini Files API delete failed with HTTP ${response.status}`);\n\t\t},\n\t};\n}\n","sourceCodeStart":137,"sourceCodeEnd":173,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/blob-broker/provider-files-gemini.ts#L137-L173","documentation":"Thrown by the Gemini provider's delete() when the supplied ProviderFileHandle was issued by a different provider (handle.provider !== \"google\"). Provider file handles are provider-scoped: a handle holding an OpenAI file id cannot be deleted through the Gemini Files API, so the library fails fast with a clear message instead of making a doomed request.","triggerScenarios":"Calling delete() on the Gemini file client with a handle whose provider field is e.g. \"openai\" — typically because the handle was returned by a different provider's upload or stored in shared state (session, DB) and passed to the wrong client.","commonSituations":"Mixing multiple blob-broker providers (OpenAI and Gemini) in one session and routing cleanup through a single client; persisting handles without the provider field and reconstructing them with the wrong client; switching model providers mid-session while retaining old file handles.","solutions":["Route each handle to the client whose provider matches handle.provider before calling delete().","Store the provider alongside the handle id in your persistence layer and look up the correct client by that field.","If migrating between providers, re-upload the file to the new provider and use the newly returned handle.","Add a guard/dispatch map in caller code: { google: geminiClient, openai: openaiClient }[handle.provider].delete(handle)."],"exampleFix":"// before\ngeminiClient.delete(handle); // handle.provider === \"openai\"\n// after\nif (handle.provider === \"google\") {\n  await geminiClient.delete(handle);\n} else {\n  await openaiClient.delete(handle);\n}","handlingStrategy":"type-guard","validationCode":null,"typeGuard":"function isGoogleHandle(h: ProviderFileHandle): h is ProviderFileHandle & { provider: \"google\" } {\n  return h.provider === \"google\";\n}\n// call site: if (!isGoogleHandle(handle)) routeToOtherProvider(handle);","tryCatchPattern":null,"preventionTips":["Always dispatch deletes through a provider-keyed map instead of calling a specific client","Persist handle.provider together with handle.id","Never share handles across sessions that switch model providers","Type the handle narrowly (branded google/openai types) so mismatches fail at compile time"],"tags":["programming","provider-mismatch","handle","gemini","api-misuse"],"backgroundTag":"provider-handle-mismatch","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}