chinabugotech/hutool · error · AIException

Video URI is empty

Error message

Video URI is empty

What it means

A precondition violation thrown by GeminiServiceImpl.downLoadVideo(videoUri, filePath) when videoUri is null, empty, or whitespace-only (StrUtil.isBlank). It is a guard before attempting the HTTP download, so no network call is made. Indicates the caller did not obtain a valid video resource URI from a completed generate-video operation.

Source

Thrown at hutool-ai/src/main/java/cn/hutool/ai/model/gemini/GeminiServiceImpl.java:136

	@Override
	public String predictVideo(String prompt) {
		final Map<String, Object> paramMap = buildPredictVideoRequestMap(prompt);
		final HttpResponse response = sendPost(getPredictVideoEndpoint(), JSONUtil.toJsonStr(paramMap));
		return response.body();
	}

	@Override
	public String getVideoOperation(String operationName) {
		String endPoint = "/" + operationName;
		final HttpResponse response = sendGet(endPoint);
		return response.body();
	}

	@Override
	public void downLoadVideo(String videoUri, String filePath) {
		if (StrUtil.isBlank(videoUri)) {
			throw new AIException("Video URI is empty");
		}
		final HttpResponse response = HttpRequest.get(videoUri)
			.header("x-goog-api-key", config.getApiKey())
			.setFollowRedirects(true)
			.executeAsync();
		if (response.isOk()) {
			response.writeBody(FileUtil.file(filePath));
		} else {
			throw new AIException("Download failed with status: " + response.getStatus());
		}
	}

	@Override
	public String textToSpeech(String prompt) {
		final Map<String, Object> paramMap = buildTextToSpeechRequestMap(prompt);
		final HttpResponse response = sendPost(getEndpoint(false), JSONUtil.toJsonStr(paramMap));
		return response.body();
	}

View on GitHub (pinned to 8870454b2a)

Solutions

  1. Poll getVideoOperation(operationName) until the operation JSON shows done == true.
  2. Extract the URI from response.generateVideoResponse.samples[].uri (or the signed URL field your Gemini version returns).
  3. Validate the extracted URI with StrUtil.isNotBlank before calling downLoadVideo.
  4. Do not pass the operation name or the prompt as the videoUri.

Example fix

// before
String op = gemini.predictVideo("a cat");
gemini.downLoadVideo(null, "/tmp/out.mp4"); // -> Video URI is empty

// after
String opJson = gemini.predictVideo("a cat");
String opName = JSONUtil.parseObj(opJson).getStr("name");
String opResult;
do {
    opResult = gemini.getVideoOperation(opName);
} while (!JSONUtil.parseObj(opResult).getBool("done", false));
String uri = JSONUtil.parseObj(opResult)
    .getByPath("response.generateVideoResponse.samples[0].uri", String.class);
gemini.downLoadVideo(uri, "/tmp/out.mp4");
Defensive patterns

Strategy: validation

Validate before calling

// Ensure a non-blank URI from a completed operation before download
if (StrUtil.isBlank(videoUri)) {
    throw new IllegalStateException("video not ready: operation not done or uri missing");
}
gemini.downLoadVideo(videoUri, filePath);

Type guard

// Narrow a parsed operation result to a downloadable URI
static String extractVideoUri(String operationJson) {
    JSONObject op = JSONUtil.parseObj(operationJson);
    if (!op.getBool("done", false)) return null;
    return op.getByPath("response.generateVideoResponse.samples[0].uri", String.class);
}

Try / catch

try {
    gemini.downLoadVideo(uri, path);
} catch (AIException e) {
    if ("Video URI is empty".equals(e.getMessage())) {
        // re-poll the operation until done, then re-extract uri
    }
    throw e;
}

Prevention

When it happens

Trigger: Calling downLoadVideo before the asynchronous video generation operation has produced a result URI; passing the operation name instead of the video URI; parsing the operation JSON incorrectly and extracting null for the videoUri field.

Common situations: Gemini video generation is asynchronous: predictVideo returns an operation name, getVideoOperation polls it, and only a done operation contains response.generateVideoResponse.samples.uri. Calling downLoadVideo with a blank value means the workflow skipped polling or parsed the wrong field.

Related errors


AI-assisted analysis of chinabugotech/hutool@8870454b2a (2026-08-14). Data as JSON: /api/errors/c6912030828993d1. Report an issue: GitHub.