{"record":{"id":"cbfb249bb8a87132","repo":"Crosstalk-Solutions/project-nomad","slug":"maximum-of-10-custom-libraries-allowed-cbfb24","errorCode":null,"errorMessage":"Maximum of 10 custom libraries allowed","messagePattern":"Maximum of 10 custom libraries allowed","errorType":"http","errorClass":null,"httpStatus":400,"severity":"warning","filePath":"admin/app/controllers/zim_controller.ts","lineNumber":197,"sourceCode":"    const payload = await request.validateUsing(selectWikipediaValidator)\n    return this.zimService.selectWikipedia(payload.optionId)\n  }\n\n  // Custom library endpoints\n\n  async listCustomLibraries({}: HttpContext) {\n    return this.zimService.listCustomLibraries()\n  }\n\n  async addCustomLibrary({ request, response }: HttpContext) {\n    const payload = await request.validateUsing(addCustomLibraryValidator)\n    assertNotPrivateUrl(payload.base_url)\n    try {\n      const source = await this.zimService.addCustomLibrary(payload.name, payload.base_url)\n      return { message: 'Custom library added', library: source }\n    } catch (error) {\n      if (error.message === 'Maximum of 10 custom libraries allowed') {\n        return response.status(400).send({ message: error.message })\n      }\n      throw error\n    }\n  }\n\n  async removeCustomLibrary({ request, response }: HttpContext) {\n    const payload = await request.validateUsing(idParamValidator)\n    try {\n      await this.zimService.removeCustomLibrary(payload.params.id)\n      return { message: 'Custom library removed' }\n    } catch (error) {\n      if (error.message === 'Custom library not found') {\n        return response.status(404).send({ message: error.message })\n      }\n      throw error\n    }\n  }\n","sourceCodeStart":179,"sourceCodeEnd":215,"githubUrl":"https://github.com/Crosstalk-Solutions/project-nomad/blob/0bd1c6f4f9888d577fe232de06ac144bb8337131/admin/app/controllers/zim_controller.ts#L179-L215","documentation":"The zim service enforces a hard cap of 10 user-defined custom library sources; addCustomLibrary throws when an 11th is attempted. The controller maps it to a 400 so the client sees a clean validation-style error instead of a 500.","triggerScenarios":"Calling POST to add a custom library when 10 custom library entries already exist in the zim settings/store (e.g. addCustomLibrary on an already-full list).","commonSituations":"Repeatedly re-adding libraries during testing without removing old ones; scripts provisioning sources accumulating entries over time; stale state persisting between environments.","solutions":["Delete an existing custom library first (removeCustomLibrary endpoint) to free a slot, then retry the add","Inspect the current custom library list via the state/read endpoint and deduplicate entries before adding","If 10 is genuinely too few for your deployment, raise the limit in zimService.addCustomLibrary or persist the list externally"],"exampleFix":"// before\nawait zimController.addCustomLibrary({ name: 'new-lib', base_url: 'https://example.com/zim' }) // 400: Maximum of 10 custom libraries allowed\n// after\nawait zimController.removeCustomLibrary(existingId)\nawait zimController.addCustomLibrary({ name: 'new-lib', base_url: 'https://example.com/zim' })","handlingStrategy":"validation","validationCode":"const libs = await api.get('/zim/state') // or the libraries list endpoint\nif (libs.customLibraries.length >= 10) {\n  throw new Error('Remove a custom library before adding another (max 10)')\n}\nawait api.post('/zim/libraries', { name, base_url })","typeGuard":null,"tryCatchPattern":"try {\n  await addCustomLibrary(name, url)\n} catch (e) {\n  if (e.status === 400 && /Maximum of 10/.test(e.message)) {\n    // prompt user to remove one, or auto-evict oldest\n  } else throw e\n}","preventionTips":["Show remaining quota (used/10) in the UI","Auto-remove replaced libraries when re-adding by name","Refresh the library list before every add"],"tags":["zim","custom-library","quota","http-400","limit-exceeded"],"backgroundTag":"resource-quota-exceeded","analyzedSha":"0bd1c6f4f9888d577fe232de06ac144bb8337131","analyzedAt":"2026-08-27T05:34:15.424Z","schemaVersion":2},"datasetVersion":"2026-08-27T08:17:20.692Z"}