immich-app/immich · warning
Machine learning request to
Error message
Machine learning request to "${url}" failed with status ${response.status}: ${response.statusText} What it means
The machine-learning repository calls the ML microservice's /predict endpoint via fetch. When the response is not ok (non-2xx), the call is not retried and this warning is logged; the caller (e.g. smart search / facial recognition job) receives no embedding result for that asset. It is a warning, not a throw — the service degrades gracefully but ML-dependent features fail.
Solutions
- Check the machine-learning container logs for the stack trace corresponding to the logged status.
- Verify IMMICH_MACHINE_LEARNING_URL points to the correct reachable host:port of the ML service.
- Restart the machine-learning container; increase its memory limit if it was OOM-killed.
- Ensure server and machine-learning images are the same version.
- If status 413/4xx, lower concurrency or image size settings for ML jobs.
Example fix
// before
const response = await fetch(new URL('predict', url), { method: 'POST', body: formData });
// after (add timeout + explicit status logging)
const response = await fetch(new URL('predict', url), { method: 'POST', body: formData, signal: AbortSignal.timeout(30_000) });
if (!response.ok) this.logger.warn(`ML predict failed: ${response.status} ${await response.text()}`); Defensive patterns
Strategy: retry
Validate before calling
const health = await fetch(new URL('ping', mlUrl)).then(r => r.ok, () => false);
if (!health) throw new Error(`ML server ${mlUrl} not ready`); Try / catch
try {
const res = await fetch(new URL('predict', url), { method: 'POST', body: formData, signal: AbortSignal.timeout(30_000) });
if (!res.ok) throw new Error(`ML ${res.status}: ${res.statusText}`);
return await res.json();
} catch (e) {
logger.warn(`ML predict failed, using fallback`, e);
return null; // degrade: skip smart-search/face features
} Prevention
- Health-check the ML container before running bulk jobs.
- Pin matching server/ML image versions.
- Give the ML container ample memory (model loading OOM is common).
- Add a fetch timeout and bounded retries with backoff.
When it happens
Trigger: A POST to `${url}predict` with form data returns a non-ok HTTP status (4xx/5xx) from the machine-learning server, e.g. during search indexing or face detection.
Common situations: ML container not fully started or crashed mid-request; model loading failure (OOM) on the ML server; version mismatch between server and ML image; wrong MACHINE_LEARNING_URL/port configured; request payload too large for the ML server.
Understand the failure class
Background: "API error: {status}" and "HTTP 401/403/404/429/5xx" errors: non-2xx HTTP responses explained — this error's family across 27 libraries.
Related errors
- await response.text()
- EOFException
- errors.unable_to_upload_file
- Failed to fetch activation key
- Machine learning request
AI-assisted analysis of immich-app/immich@e55ac299a4 (2026-09-15).
Data as JSON: /api/errors/ae3342139d5d90b2.
Report an issue: GitHub.
Appendix: source
Thrown at server/src/repositories/machine-learning.repository.ts:177
return this.healthyMap[url];
}
private async predict<T>(payload: ModelPayload, config: MachineLearningRequest): Promise<T> {
const formData = await this.getFormData(payload, config);
for (const url of [
// try healthy servers first
...this.config.urls.filter((url) => this.isHealthy(url)),
...this.config.urls.filter((url) => !this.isHealthy(url)),
]) {
try {
const response = await fetch(new URL('predict', url), { method: 'POST', body: formData });
if (response.ok) {
this.setHealthy(url, true);
return response.json();
}
this.logger.warn(
`Machine learning request to "${url}" failed with status ${response.status}: ${response.statusText}`,
);
} catch (error: Error | unknown) {
this.logger.warn(`Machine learning request to "${url}" failed`, error);
}
this.setHealthy(url, false);
}
throw new Error(`Machine learning request '${JSON.stringify(config)}' failed for all URLs`);
}
async detectFaces(imagePath: string, { modelName, minScore }: FaceDetectionOptions) {
const request = {
[ModelTask.FACIAL_RECOGNITION]: {
[ModelType.DETECTION]: { modelName, options: { minScore } },
[ModelType.RECOGNITION]: { modelName },
},View on GitHub (pinned to e55ac299a4)