Wei-Shaw/sub2api · warning
profile.avatar.compressTooLarge
Error message
profile.avatar.compressTooLarge
What it means
In frontend/src/components/user/profile/ProfileAvatarCard.vue:188, compressAvatarFile() iterates a ladder of downscale steps (avatarScaleSteps) and webp quality steps (avatarQualitySteps); if no scale/quality combination produces a blob under targetAvatarUploadBytes, it throws the localized 'profile.avatar.compressTooLarge'. The image cannot be shrunk to the upload budget — typically a huge source image or a pathological image that webp encodes poorly.
Source
Thrown at frontend/src/components/user/profile/ProfileAvatarCard.vue:188
for (const scale of avatarScaleSteps) {
const width = Math.max(1, Math.round(image.naturalWidth * scale))
const height = Math.max(1, Math.round(image.naturalHeight * scale))
canvas.width = width
canvas.height = height
ctx.clearRect(0, 0, width, height)
ctx.drawImage(image, 0, 0, width, height)
for (const quality of avatarQualitySteps) {
const blob = await canvasToBlob(canvas, 'image/webp', quality)
if (blob.size <= targetAvatarUploadBytes) {
const fileName = file.name.replace(/\.[^.]+$/, '') || 'avatar'
return new File([blob], `${fileName}.webp`, { type: 'image/webp' })
}
}
}
throw new Error(t('profile.avatar.compressTooLarge'))
}
async function prepareAvatarUpload(file: File): Promise<File> {
if (!file.type.startsWith('image/')) {
throw new Error(t('profile.avatar.invalidType'))
}
if (file.type === 'image/gif') {
if (file.size > targetAvatarUploadBytes) {
throw new Error(t('profile.avatar.gifTooLarge'))
}
return file
}
if (file.size <= targetAvatarUploadBytes) {
return file
}
return compressAvatarFile(file)
}
View on GitHub (pinned to 073e92d171)
Solutions
- Extend the scale ladder with smaller final scales (e.g., down to 128px) so the last step nearly always fits.
- Detect toBlob('image/webp') support (Safari fallback) and use 'image/jpeg' quality ladder as fallback output type.
- Reject early with a clear message when naturalWidth*smallestScale still can't plausibly fit, before doing the expensive loop.
- Raise targetAvatarUploadBytes if the product allows larger avatars.
Example fix
// before
for (const scale of avatarScaleSteps) {
// ... for (const quality of avatarQualitySteps) { ... }
}
throw new Error(t('profile.avatar.compressTooLarge'))
// after
const outType = canvasToBlobSupportsWebp() ? 'image/webp' : 'image/jpeg'
for (const scale of avatarScaleSteps) {
for (const quality of avatarQualitySteps) {
const blob = await canvasToBlob(canvas, outType, quality)
if (blob.size <= targetAvatarUploadBytes) return new File([blob], `${fileName}.${outType.split('/')[1]}`, { type: outType })
}
}
throw new Error(t('profile.avatar.compressTooLarge')) Defensive patterns
Strategy: validation
Validate before calling
// Reject implausibly huge images before the expensive compression ladder:
const minPixels = 128 * 128;
if (image.naturalWidth * image.naturalHeight < minPixels && file.size > targetAvatarUploadBytes * 2) {
throw new Error(t('profile.avatar.compressTooLarge'));
} Try / catch
try { avatar = await compressAvatarFile(file); }
catch (e) {
if (e.message === t('profile.avatar.compressTooLarge')) { showSizeHint(); return; }
throw e;
} Prevention
- Extend the scale ladder to very small final dimensions so the last rung nearly always fits
- Detect webp toBlob support (Safari) and fall back to jpeg quality steps
- Show the target byte budget in the UI before upload
When it happens
Trigger: Uploading a very high-resolution photo (e.g., 8000×6000) where even the smallest scale step keeps the encode above targetAvatarUploadBytes; images with noisy/photographic content that resist webp compression; browsers whose canvas.toBlob for image/webp falls back to png (older Safari), yielding larger blobs than expected.
Common situations: Panorama or RAW-export uploads; screenshots with gradients; Safari < 14 lacking solid webp encoding so every quality step returns similar sizes; targetAvatarUploadBytes set very low by configuration.
Related errors
- profile.avatar.compressFailed
- profile.avatar.gifTooLarge
- profile.avatar.invalidType
- Passkeys are not supported by this browser
- Passkey sign-in was cancelled
AI-assisted analysis of Wei-Shaw/sub2api@073e92d171 (2026-08-15).
Data as JSON: /api/errors/d1d2553684dede8f.
Report an issue: GitHub.