Get hands-on experience with 20+ free Google Cloud products and $300 in free credit for new customers.

Imagen fails to upscale when using a gsutil URL

Hello all,

The Imagen docs say that I can upscale an image using a gcsUri [1]. However, repeated attempts at making this work have been met with failure. I am running the following node code (I experience the same error in python). The error I'm getting back from the API is `RecvAsync is cancelled`

Here is my node reproduction:

 

 

 

import { GoogleAuth } from 'google-auth-library';

const url = 'https://us-central1-aiplatform.googleapis.com/v1/projects/gemini-image-generation-454107/locations/us-central1/publishers/google/models/imagegeneration@002:predict';

async function getAccessToken() {
  const auth = new GoogleAuth({
    keyFile: 'gemini-image-generation-454107-6fb54a12791d.json',
    scopes: ['https://www.googleapis.com/auth/cloud-platform'],
  });

  const client = await auth.getClient();

  const headers = await client.getRequestHeaders();
  const token = headers['Authorization'].split(' ')[1];
  return token;
}

async function upscaleImage(gsUri) {
  const token = await getAccessToken();

  const headers = {
    'Authorization': `Bearer ${token}`,
    'Content-Type': 'application/json'
  };

  const payload = {
    instances: [
      {
        image: {
          gcsUri: gsUri
        }
      }
    ],
    parameters: {
      sampleCount: 1,
      mode: "upscale",
      upscaleConfig: {
        upscaleFactor: "x2"
      }
    }
  };

  const response = await fetch(url, {
    method: 'POST',
    headers,
    body: JSON.stringify(payload)
  });

  if (response.ok) {
    console.log("Upscale success!");
    return response.json();
  } else {
    const errorText = await response.text();
    console.error(`Failed with status ${response.status}: ${errorText}`);
    throw new Error(`Request failed with status ${response.status}: ${errorText}`);
  }
}

const result = await upscaleImage('gs://upscaler-photo-upload/apple_2.png');
console.log('Upscale result:', result);

 

 

This results in the following failure:

Screenshot 2025-03-30 at 12.01.06.png

Is this functionality not actually supported?

Thank you,

Lou

[1] See 'gcsUri' in the JSON body here: https://cloud.google.com/vertex-ai/generative-ai/docs/image/upscale-image

0 1 25
1 REPLY 1

So I have some additional findings on this if anyone from the Imagen team is ability to assist:

- Using the `gcsUri` parameter never works, regardless of image size. Making a request with this parameter always results in a 499 with the error `RecvAsync is cancelled`

- If instead I use the `bytesBase64Encoded` param, then the request succeeds for small images, and works really well, completing quickly and with great results. As soon as the image is a medium size (say 3MB), the script will hang for a minute and then respond with:

{
"error": {
"code": 400,
"message": "Image editing failed with the following error: Response size too large. Received at least 31544347 bytes; max is 31457280.",
"status": "FAILED_PRECONDITION"
}
}

 

FWIW that image was originally 1920 × 2880 (which is not abnormally large) and I tried to upscale it 2x.

Here is the script that I used:

 

import { readFile } from 'fs/promises';
import { GoogleAuth } from 'google-auth-library';
import { Storage } from '@google-cloud/storage';
import path from 'path';
import fs from 'fs';

import { writeFile } from 'fs/promises';


// URL for the Vertex AI upscale endpoint
const url = 'https://us-central1-aiplatform.googleapis.com/v1/projects/gemini-image-generation-454107/locations/us-central1/publishers/google/models/imagen-3.0-generate-002:predict';

// Convert image file to base64
async function imageToBase64(imagePath) {
  const imageData = await readFile(imagePath);
  return imageData.toString('base64');
}

// Authenticate using GoogleAuth and get access token explicitly
async function getAccessToken() {
  const auth = new GoogleAuth({
    keyFile: 'gemini-image-generation-454107-6fb54a12791d.json',
    scopes: ['https://www.googleapis.com/auth/cloud-platform'],
  });

  const client = await auth.getClient();

  // Important: Use getRequestHeaders to get a proper auth header
  const headers = await client.getRequestHeaders();
  const token = headers['Authorization'].split(' ')[1]; // Removes the "Bearer " prefix
  return token;
}

// Function to upscale the image
async function upscaleImage(base64Image) {
  const token = await getAccessToken();

  const headers = {
    'Authorization': `Bearer ${token}`,
    'Content-Type': 'application/json'
  };

  const payload = {
    instances: [
      {
        // prompt: "",
        image: {
          // gcsUri: "gs://delete-this-bucket-it-is-public-testing/apple_icon.png",
          //gcsUri: "gs://delete-this-bucket-it-is-public-testing/blob.b64",
          mimeType: "image/png",
          // mimeType: "image/png"
          bytesBase64Encoded: base64Image
        }
      }
    ],
    parameters: {
      sampleCount: 1,
      mode: "upscale",
      upscaleConfig: {
        upscaleFactor: "x2"
      },
      storageUri: "gs://upscaler-photo-upload/output",
    }
  };

  const response = await fetch(url, {
    method: 'POST',
    headers,
    body: JSON.stringify(payload)
  });

  if (response.ok) {
    console.log("Upscale success!");
    return response.json();
  } else {
    const errorText = await response.text();
    console.error(`Failed with status ${response.status}: ${errorText}`);
    throw new Error(`Request failed with status ${response.status}: ${errorText}`);
  }
}

// Write the base64 string to blob.b64
async function saveBase64ToFile(base64Data) {
  try {
    await writeFile('blob.b64', base64Data, 'utf8');
    console.log('Saved as blob.b64');
  } catch (err) {
    console.error('Error saving file:', err);
  }
}


// Main function to run the upscale example
async function main() {
  try {
    const base64 = await imageToBase64('big_pink.png');
    //const base64 = await imageToBase64('medium_pink.png');
    // await saveBase64ToFile(base64);
    const result = await upscaleImage(base64);
    console.log('Upscale result:', result);
  } catch (error) {
    console.error('Error:', error);
  }
}