immich-app/immich · error · BadRequestException
Asset does not have valid dimensions
Error message
Asset does not have valid dimensions
What it means
When the target asset has edits (crops/rotations from the edit stack), the service must convert client coordinates from the edited preview space to the original image space. That conversion requires asset.width/height and exifInfo.exifImageWidth/exifImageHeight; if any is missing or zero, it throws BadRequestException('Asset does not have valid dimensions') instead of computing a bogus region.
Solutions
- Remove the asset's edits (revert to original) before updating the face region, so no coordinate conversion is needed.
- Re-upload or re-process the asset so width/height and EXIF dimensions are populated (run metadata extraction job).
- Verify the file's EXIF; inject missing dimensions via exiftool if the source lacks them.
- Retry after the asset finishes processing (check asset.status is ready and exifInfo present).
Example fix
// before
await updateFaceRegion({ assetId, x, y, width, height, imageWidth }); // asset has edits but no EXIF dims
// after
await api.assetsApi.replaceAsset({ id: assetId, ... }); // or revert edits first
await updateFaceRegion({ assetId, x, y, width, height, imageWidth }); Defensive patterns
Strategy: fallback
Validate before calling
const asset = await api.assetsApi.getAssetInfo({ id: assetId });
const hasEdits = (asset.edits?.length ?? 0) > 0;
const dimsOk = !hasEdits || (asset.exifInfo?.exifImageWidth && asset.exifInfo?.exifImageHeight);
if (!dimsOk) throw new Error('Asset lacks EXIF dimensions required for edited-coordinate conversion'); Type guard
function hasValidDimensions(asset) {
return Boolean(asset.width && asset.height && asset.exifInfo?.exifImageWidth && asset.exifInfo?.exifImageHeight);
} Try / catch
try {
await updateFaceRegion(dto);
} catch (e) {
if (e.status === 400 && String(e.message).includes('valid dimensions')) {
// fall back to reverting edits or re-running the metadata extraction job
} else throw e;
} Prevention
- Ensure metadata extraction completes before editing faces on edited assets.
- Avoid stripping EXIF from uploads; inject dimensions if missing.
- Prefer reverting edits on the asset before sending preview coordinates.
When it happens
Trigger: Updating a face region on an asset that has edits but lacks valid width/height metadata or EXIF image dimensions (missing EXIF, dimension-less sidecar, corrupted metadata, or media not yet fully processed).
Common situations: Screenshots or images stripped of EXIF that were then edited, assets mid-ingestion where dimensions aren't computed yet, corrupted metadata after restore, or third-party uploads without dimensions.
Understand the failure class
Background: "is required", "must be set", "missing required field": configuration validation errors across open-source libraries — this error's family across 36 libraries.
Related errors
- Invalid assetId for feature face or asset is offline
- Asset dimensions are not available for editing
- Asset not found
- Asset not found
- Asset not in stack
AI-assisted analysis of immich-app/immich@f48d4b3321 (2026-09-15).
Data as JSON: /api/errors/0e6a3433e18d9b55.
Report an issue: GitHub.
Appendix: source
Thrown at server/src/services/person.service.ts:701
const [asset, person] = await Promise.all([
this.assetRepository.getById(dto.assetId, { edits: true, exifInfo: true }),
this.findOrFail(auth, dto.personId),
]);
if (!asset) {
throw new NotFoundException('Asset not found');
}
const edits = asset.edits || [];
let topLeft: Point = { x: dto.x, y: dto.y };
let bottomRight: Point = { x: dto.x + dto.width, y: dto.y + dto.height };
// the coordinates received from the client are based on the edited preview image
// we need to convert them to the coordinate space of the original unedited image
if (edits.length > 0) {
if (!asset.width || !asset.height || !asset.exifInfo?.exifImageWidth || !asset.exifInfo?.exifImageHeight) {
throw new BadRequestException('Asset does not have valid dimensions');
}
// convert from preview to full dimensions
const scaleFactor = asset.width / dto.imageWidth;
topLeft = { x: topLeft.x * scaleFactor, y: topLeft.y * scaleFactor };
bottomRight = { x: bottomRight.x * scaleFactor, y: bottomRight.y * scaleFactor };
const [invertedTopLeft, invertedBottomRight] = transformPoints(
[topLeft, bottomRight],
edits,
{ width: asset.width, height: asset.height },
{ inverse: true },
).points;
// make sure topLeft is top-left and bottomRight is bottom-right
topLeft = {
x: Math.min(invertedTopLeft.x, invertedBottomRight.x),
y: Math.min(invertedTopLeft.y, invertedBottomRight.y),View on GitHub (pinned to f48d4b3321)