mudler/LocalAI · error · Error
No job ID returned from server
Error message
No job ID returned from server
What it means
ImportModel.jsx calls modelsApi.importUri to start a URI-based (e.g. HuggingFace) model import and expects the response to carry a job identifier under uuid or ID, which startJobPolling then tracks. When neither field is present the client cannot poll the job, so it throws rather than showing a fake 'started' state. The next lines' ambiguity branch (HTTP 400 {error:'ambiguous import'}) is a different, handled path — this throw is for a 2xx response with an unexpected body.
Source
Thrown at core/http/react-ui/src/pages/ImportModel.jsx:307
if (prefs.enable_parameters.trim()) prefsObj.enable_parameters = prefs.enable_parameters.trim()
if (prefs.cuda) prefsObj.cuda = true
customPrefs.forEach(cp => {
if (cp.key.trim() && cp.value.trim()) prefsObj[cp.key.trim()] = cp.value.trim()
})
const result = await modelsApi.importUri({
uri: importUri.trim(),
preferences: Object.keys(prefsObj).length > 0 ? prefsObj : null,
})
const hasSize = result.estimated_size_display && result.estimated_size_display !== '0 B'
const hasVram = result.estimated_vram_display && result.estimated_vram_display !== '0 B'
if (hasSize || hasVram) {
setEstimate({ sizeDisplay: result.estimated_size_display || '', vramDisplay: result.estimated_vram_display || '' })
}
const jobId = result.uuid || result.ID
if (!jobId) throw new Error('No job ID returned from server')
addToast(t('toasts.started'), 'success')
// Clear any prior ambiguity alert once the server accepts the import.
setAmbiguity(null)
startJobPolling(jobId)
} catch (err) {
// Structured ambiguity response — render the inline picker instead of
// a toast. The server returns HTTP 400 with { error, modality,
// candidates } which api.handleResponse attaches as err.body.
if (err?.status === 400 && err?.body && err.body.error === 'ambiguous import') {
setAmbiguity({
modality: err.body.modality || '',
candidates: Array.isArray(err.body.candidates) ? err.body.candidates : [],
})
setIsSubmitting(false)
return
}
addToast(t('toasts.startImportFailed', { message: err.message }), 'error')View on GitHub (pinned to 44413a9d06)
Solutions
- Align versions: run a LocalAI server of the same generation as the React UI (rebuild/update the backend)
- Inspect the actual response: console.log(result) or curl -X POST $BASE/importuri to see which field name the server uses
- If the server completed synchronously, skip polling: treat presence of the model in /v1/models as success instead of throwing
- Add the server's field name to the jobId lookup (see exampleFix)
Example fix
// before
const jobId = result.uuid || result.ID
if (!jobId) throw new Error('No job ID returned from server')
// after — tolerate shape drift
const jobId = result.uuid || result.ID || result.id || result.job?.uuid
if (!jobId) throw new Error('No job ID returned from server') Defensive patterns
Strategy: validation
Validate before calling
// defensive shape check before relying on the job id
function extractJobId(result) {
if (!result || typeof result !== 'object') return null
return result.uuid ?? result.ID ?? result.id ?? null
} Type guard
function isImportJobResponse(result) {
return Boolean(result) && typeof result === 'object' && ('uuid' in result || 'ID' in result)
} Try / catch
try {
const result = await modelsApi.importUri({ uri, preferences })
const jobId = result.uuid || result.ID || result.id
if (!jobId) throw new Error('No job ID returned from server')
startJobPolling(jobId)
} catch (err) {
if (err?.status === 400 && err?.body?.error === 'ambiguous import') setAmbiguity(err.body)
else if (err.message === 'No job ID returned from server') addToast('server version mismatch — update LocalAI', 'error')
else addToast(err.message, 'error')
} Prevention
- Keep the React UI and the LocalAI backend on matching versions — job fields are part of the contract
- Log the raw import response body when the id lookup fails to identify field drift quickly
- Treat missing job id as a distinct, named error so users get a version-mismatch hint, not a generic failure
When it happens
Trigger: The server accepts the import (2xx) but returns a body without uuid/ID: version mismatch where an older/newer backend renamed the field (e.g. returns {id: ...} or {job: ...}), a proxy rewriting the response, or a server that synchronously completed the import and returned a different shape. The field check result.uuid || result.ID covers both casings, so genuinely missing means shape drift.
Common situations: React UI (newer) talking to an older LocalAI binary whose import-uri endpoint predates job-based responses; response mangled by an intercepting proxy; API contract changed in a fork.
Related errors
AI-assisted analysis of mudler/LocalAI@44413a9d06 (2026-08-15).
Data as JSON: /api/errors/8058e1bf102820c2.
Report an issue: GitHub.