403 PERMISSION_DENIED only when generateContent references a Files API file — upload and text-only requests both succeed

Since 2026-08-14 JST, every transcription request from my app fails with 403 PERMISSION_DENIED. The application code has not changed for over a week, and the same code path worked the day before.

  • Last success: 2026-08-13 18:52 JST
  • First failure: 2026-08-14 21:50 JST
  • Model: gemini-3.6-flash
  • API: Gemini Developer API, key sent in the x-goog-api-key header
  • Client: iOS app (Swift, URLSession), also reproduced with plain curl

The error body is exactly this, with no details field, which makes it hard to tell what is actually being denied:

{"error":{"code":403,"message":"The caller does not have permission","status":"PERMISSION_DENIED"}}

What I narrowed it down to

The failure is specific to referencing an uploaded file. Everything else on the same credential works:

Request Result
POST /upload/v1beta/files (resumable start + finalize) 200 — file created
GET /v1beta/files/{id} 200 — "state": "ACTIVE"
GET /v1beta/files 200 — file listed
POST /v1beta/models/gemini-3.6-flash:generateContent, text part only 200 — normal response
POST .../generateContent with fileData.fileUri pointing at that file 403
POST .../generateContent with the same audio as inlineData (base64) 200 — normal response

So the upload succeeds, the file reports state: ACTIVE, and the same credential can both read and list it — but referencing it from generateContent is denied.

I also tried with a freshly issued credential and got identical results, so rotating the key does not help.

Workaround

Sending the audio as inlineData instead of going through the Files API works normally, and returns a correct transcription with the same responseSchema. This only holds while the payload stays under the request size limit, so it is not a fix for large files.

Questions

  1. Was there an intentional change to how Files API resources are authorized in generateContent? I could not find anything in the release notes.
  2. Could the 403 response include a details / reason field? With just “The caller does not have permission” there is no way to tell whether this is the key, the project, the file resource, or the model.

There are other reports of 403 PERMISSION_DENIED from around the same time, but those describe all requests failing, whereas mine is isolated to file references — so I am not sure it is the same root cause:

Update: The issue resolved itself overnight without any changes on my side. This morning, the exact same request started working normally.

I didn’t change the API key, permissions, uploaded file, request payload, or code, so this looks like it may have been a temporary backend/permission propagation issue.