Crosstalk-Solutions/project-nomad · warning
Custom library not found
Error message
Custom library not found
What it means
removeCustomLibrary throws when the supplied id does not match any stored custom library source; the controller translates it into a 404. Typically caused by removing an already-deleted library or passing a wrong id.
Source
Thrown at admin/app/controllers/zim_controller.ts:210
try {
const source = await this.zimService.addCustomLibrary(payload.name, payload.base_url)
return { message: 'Custom library added', library: source }
} catch (error) {
if (error.message === 'Maximum of 10 custom libraries allowed') {
return response.status(400).send({ message: error.message })
}
throw error
}
}
async removeCustomLibrary({ request, response }: HttpContext) {
const payload = await request.validateUsing(idParamValidator)
try {
await this.zimService.removeCustomLibrary(payload.params.id)
return { message: 'Custom library removed' }
} catch (error) {
if (error.message === 'Custom library not found') {
return response.status(404).send({ message: error.message })
}
throw error
}
}
async browseLibrary({ request, response }: HttpContext) {
const payload = await request.validateUsing(browseLibraryValidator)
try {
return await this.zimService.browseLibraryUrl(payload.url)
} catch (error) {
if (error.message?.includes('loopback or link-local')) {
return response.status(400).send({ message: error.message })
}
return response.status(502).send({
message: 'Could not fetch directory listing from the provided URL',
})
}
}View on GitHub (pinned to 0bd1c6f4f9)
Solutions
- Fetch the current custom library list and use an id from that fresh response
- Treat 404 as success if your goal is removal (the library is already gone) — make the delete idempotent client-side
- If the id comes from UI state, refresh the list after every mutation to avoid stale ids
Example fix
// before
await api.delete(`/zim/libraries/${staleId}`) // 404
// after
const libs = await api.get('/zim/libraries')
const target = libs.find(l => l.name === 'my-lib')
if (target) await api.delete(`/zim/libraries/${target.id}`) Defensive patterns
Strategy: try-catch
Validate before calling
const libs = await api.get('/zim/libraries')
if (!libs.some(l => l.id === id)) return // already gone — nothing to do
await api.delete(`/zim/libraries/${id}`) Try / catch
try {
await api.delete(`/zim/libraries/${id}`)
} catch (e) {
if (e.status === 404) return // treat as success: already removed
throw e
} Prevention
- Make delete idempotent in the client
- Always derive ids from a fresh list fetch
- Refresh UI state after every mutation
When it happens
Trigger: DELETE to the custom-library route with an id that was never added or was already removed; stale id held by the UI after another client/session removed it.
Common situations: Two admin sessions racing to remove the same library; frontend state out of sync with server after a refresh elsewhere; copy/paste or UUID typo in the id param.
Understand the failure class
Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.
Related errors
- Maximum of 10 custom libraries allowed
- Failed to update chat session
- Failed to delete chat session
- Failed to fetch remote ZIM files.
- Service ${params.name} not found
AI-assisted analysis of Crosstalk-Solutions/project-nomad@0bd1c6f4f9 (2026-08-27).
Data as JSON: /api/errors/bcbdcc385f4317dc.
Report an issue: GitHub.