🎞️ fix: Surface Clear Error for Unprocessable Gemini YouTube Videos (#14396)

Google rejects a YouTube video it cannot ingest with a generic
`400 INVALID_ARGUMENT` that names no cause, which LibreChat relayed
verbatim. Attribute the failure using request context instead: when a
Google/Vertex turn carried an injected YouTube video part and the
provider returns that generic rejection, map it to a typed error the
client localizes.

Verified against the live API: a public 9h15m video is refused this way
on gemini-2.5-flash, 3.5-flash, 3.5-flash-lite and 3.6-flash, including
at MEDIA_RESOLUTION_LOW, while a short video with an identical payload
succeeds. Duration is the dominant trigger; region and access
restrictions return the same response, so the copy leads with length
without overclaiming.

A duration preflight was evaluated and skipped: oEmbed does not expose
duration, leaving only watch-page scraping — a blocking call against
undocumented markup from rate-limited datacenter IPs that would fail
open and still need this mapping underneath.
This commit is contained in:
Danny Avila 2026-07-22 12:11:06 -04:00 committed by GitHub
parent 337facb4f0
commit ad5bb477af
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 356 additions and 2 deletions

View file

@ -70,7 +70,9 @@ const {
buildSkillPrimeContentParts,
buildInitialToolSessions,
hasUrlContextTool,
hasYouTubeVideoParts,
appendYouTubeVideoParts,
resolveGoogleVideoError,
resolveYouTubeInjectionConfig,
decrementPendingRequest,
maybePrewarmCodeSandbox,
@ -600,6 +602,9 @@ class AgentClient extends BaseClient {
max,
mimeType,
});
/** Google rejects an unusable video with a generic `INVALID_ARGUMENT` that names no cause,
* so `#sendCompletion` can only attribute one by knowing this turn carried a video. */
this.injectedYouTubeVideo = hasYouTubeVideoParts(latestFormatted.content);
}
payload = formattedMessages;
@ -1904,9 +1909,16 @@ class AgentClient extends BaseClient {
'[api/server/controllers/agents/client.js #sendCompletion] Unhandled error type',
err,
);
const videoError = resolveGoogleVideoError({
error: err,
provider: this.options.agent?.provider,
hasYouTubeVideo: this.injectedYouTubeVideo,
});
this.contentParts.push({
type: ContentTypes.ERROR,
[ContentTypes.ERROR]: `An error occurred while processing the request${err?.message ? `: ${err.message}` : ''}`,
[ContentTypes.ERROR]:
videoError ??
`An error occurred while processing the request${err?.message ? `: ${err.message}` : ''}`,
});
}
} finally {