immich-app/immich · error · BadRequestException
Invalid assetId for feature face or asset is offline
Error message
Invalid assetId for feature face or asset is offline
What it means
Thrown by PersonService.update when dto.featureFaceAssetId is set but personRepository.getForFeatureFaceUpdate({ personId, assetId }) returns null. The query requires the asset to be readable by the caller AND contain a face assigned to this person AND the asset file to be present (not offline). BadRequestException -> HTTP 400.
Source
Thrown at server/src/services/person.service.ts:199
isHidden: dto.isHidden,
isFavorite: dto.isFavorite,
color: dto.color,
});
return mapPerson(person);
}
async update(auth: AuthDto, id: string, dto: PersonUpdateDto): Promise<PersonResponseDto> {
await this.requireAccess({ auth, permission: Permission.PersonUpdate, ids: [id] });
const { name, birthDate, isHidden, featureFaceAssetId: assetId, isFavorite, color } = dto;
// TODO: set by faceId directly
let faceId: string | undefined;
if (assetId) {
await this.requireAccess({ auth, permission: Permission.AssetRead, ids: [assetId] });
const face = await this.personRepository.getForFeatureFaceUpdate({ personId: id, assetId });
if (!face) {
throw new BadRequestException('Invalid assetId for feature face or asset is offline');
}
faceId = face.id;
}
const person = await this.personRepository.update({
id,
faceAssetId: faceId,
name,
birthDate,
isHidden,
isFavorite,
color,
});
if (assetId) {
await this.jobRepository.queue({ name: JobName.PersonGenerateThumbnail, data: { id } });
}View on GitHub (pinned to 199723261c)
Solutions
- Use an asset that visibly contains a face for this person (check the asset's people/faces list first).
- Re-run face detection on the asset so a face row exists.
- If the asset is offline, restore the file to its storage path before selecting it.
Example fix
// before
const face = await this.personRepository.getForFeatureFaceUpdate({ personId: id, assetId });
if (!face) {
throw new BadRequestException('Invalid assetId for feature face or asset is offline');
}
// after (split the two distinct failure modes)
const face = await this.personRepository.getForFeatureFaceUpdate({ personId: id, assetId });
if (!face) {
const asset = await this.assetRepository.getById(assetId);
throw new BadRequestException(
asset?.isOffline ? 'Asset is offline' : 'Asset has no face for this person',
);
} Defensive patterns
Strategy: validation
Validate before calling
// Before selecting a feature face, confirm the asset has a face for this person.
const faces = await assetService.getFaces(auth, assetId);
if (!faces.some((f) => f.personId === personId)) {
throw new Error('Cannot use this asset: no face for the target person');
}
await personService.update(auth, personId, { featureFaceAssetId: assetId }); Type guard
const assetHasFaceForPerson = (faces: AssetFace[], personId: string): boolean => faces.some((f) => f.personId === personId);
Try / catch
try {
await personService.update(auth, id, { featureFaceAssetId: assetId });
} catch (e) {
if (e instanceof BadRequestException && /offline|feature face/i.test(e.message)) {
// tell the user to re-run face detection or pick another asset
}
throw e;
} Prevention
- Only offer assets that contain a face for the person in the feature-face picker.
- Re-run face detection if the asset list is empty.
- Restore offline assets to storage before using them as a feature face source.
When it happens
Trigger: PUT /people/{id} with featureFaceAssetId pointing at an asset that has no face for this person, an asset that is offline (file missing from storage), or an asset the user can read but that lacks a usable face.
Common situations: Selecting a feature face from an asset after the face was reassigned to another person; the asset's original file was moved offline; choosing an asset from before re-running face detection that has no detected face.
Related errors
- Asset does not have valid dimensions
- Cannot merge a person into themselves
- Asset not found
- May not request original file
- Asset not found or asset is not a video
AI-assisted analysis of immich-app/immich@199723261c (2026-08-12).
Data as JSON: /api/errors/ad00eefa119fb651.
Report an issue: GitHub.