can1357/oh-my-pi · error

Gemini Files API finalized file state is not ACTIVE

Error message

Gemini Files API finalized file state is not ACTIVE

What it means

parseFinalizedFile() rejects the finalize response when file.state is a valid string but not exactly "ACTIVE". Gemini uploads can return states like PROCESSING, FAILED, or DISABLED; this library only supports the synchronous-finalize contract where the file is immediately usable, so any other state aborts the upload.

Source

Thrown at packages/coding-agent/src/blob-broker/provider-files-gemini.ts:42

	try {
		return responseObject((await response.json()) as unknown, context);
	} catch (error) {
		if (error instanceof Error && error.message.startsWith("Gemini Files API")) throw error;
		throw new Error(`Gemini Files API ${context} response is not valid JSON`);
	}
}

function requireString(value: unknown, field: string): string {
	if (typeof value !== "string" || value.length === 0) {
		throw new Error(`Gemini Files API finalize response is missing ${field}`);
	}
	return value;
}

function parseFinalizedFile(payload: Record<string, unknown>): GeminiFileResource {
	const file = responseObject(payload.file, "finalize file");
	const state = requireString(file.state, "file.state");
	if (state !== "ACTIVE") throw new Error("Gemini Files API finalized file state is not ACTIVE");

	const name = requireString(file.name, "file.name");
	if (!/^files\/[^/]+$/.test(name)) {
		throw new Error("Gemini Files API finalize response contains an invalid file.name");
	}
	const uri = requireString(file.uri, "file.uri");
	const mimeType = requireString(file.mimeType, "file.mimeType");
	const expirationTime = requireString(file.expirationTime, "file.expirationTime");
	const expiresAt = Date.parse(expirationTime);
	if (!Number.isFinite(expiresAt)) {
		throw new Error("Gemini Files API finalize response contains an invalid file.expirationTime");
	}
	return { name, uri, mimeType, expiresAt };
}

function isOfficialGeminiModel(model: Model): boolean {
	if (model.provider !== "google" || model.api !== "google-generative-ai") return false;
	try {

View on GitHub (pinned to 9690622007)

Solutions

  1. Inspect the returned state value — FAILED/DISABLED means the content was rejected; pick a different file or encoding.
  2. For PROCESSING, poll GET /v1beta/{file.name} (with x-goog-api-key) until state becomes ACTIVE, then reference it.
  3. Verify the file's MIME type is supported by the Gemini Files API.
  4. Retry smaller/simpler files to confirm the flow works, isolating content-specific rejection.

Example fix

// before: only accepting ACTIVE synchronously
await client.upload(request);
// after: poll until ACTIVE if the provider returns PROCESSING
const handle = await client.upload(request).catch(e => {
  if (String(e.message).includes("state is not ACTIVE")) return pollUntilActive(handleName);
  throw e;
});
Defensive patterns

Strategy: validation

Validate before calling

const SUPPORTED = ["image/png", "image/jpeg", "image/webp", "application/pdf", "text/plain", "audio/wav", "audio/mp3"];
if (!SUPPORTED.includes(request.mimeType)) {
  throw new Error(`MIME type ${request.mimeType} likely unsupported by Gemini Files API`);
}

Type guard

null

Try / catch

try {
  const handle = await client.upload(request);
} catch (error) {
  if (error instanceof Error && error.message.includes("state is not ACTIVE")) {
    // file rejected or still processing: poll GET /v1beta/{name} or surface rejection to the user
  } else throw error;
}

Prevention

When it happens

Trigger: The 'upload, finalize' POST returns a file whose state is "PROCESSING" (async processing), "FAILED" (Google rejected the content, e.g. unsupported/unsafe file), or "DISABLED" (policy-flagged).

Common situations: Uploading file types that Gemini processes asynchronously (video, large files); content filtered by safety/policy systems (state FAILED/DISABLED); temporary Google-side processing delays.

Related errors


AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31). Data as JSON: /api/errors/672b1e7a1ee2eabe. Report an issue: GitHub.