{"record":{"id":"32e3d2788153410e","repo":"Mintplex-Labs/anything-llm","slug":"unprocessable-entity","errorCode":null,"errorMessage":"Unprocessable Entity","messagePattern":"Unprocessable Entity","errorType":"http","errorClass":null,"httpStatus":422,"severity":"warning","filePath":"server/endpoints/system.js","lineNumber":1363,"sourceCode":"        // Valid user running owns the preset if user session is valid.\n        const ownsPreset = await SlashCommandPresets.get({\n          userId: user?.id ?? null,\n          id: Number(slashCommandId),\n        });\n        if (!ownsPreset)\n          return response.status(404).json({ message: \"Preset not found\" });\n\n        const updates = {\n          command: formattedCommand,\n          prompt: String(prompt),\n          description: String(description),\n        };\n\n        const preset = await SlashCommandPresets.update(\n          Number(slashCommandId),\n          updates\n        );\n        if (!preset) return response.sendStatus(422);\n        response.status(200).json({ preset: { ...ownsPreset, ...updates } });\n      } catch (error) {\n        console.error(\"Error updating slash command preset:\", error);\n        response.status(500).json({ message: \"Internal server error\" });\n      }\n    }\n  );\n\n  app.delete(\n    \"/system/slash-command-presets/:slashCommandId\",\n    [validatedRequest, flexUserRoleValid([ROLES.all])],\n    async (request, response) => {\n      try {\n        const { slashCommandId } = request.params;\n        const user = await userFromSession(request, response);\n\n        // Valid user running owns the preset if user session is valid.\n        const ownsPreset = await SlashCommandPresets.get({","sourceCodeStart":1345,"sourceCodeEnd":1381,"githubUrl":"https://github.com/Mintplex-Labs/anything-llm/blob/526360e320da9d1b36074be5ed64fe76e5bbfbbd/server/endpoints/system.js#L1345-L1381","documentation":"Returned by POST /system/slash-command-presets/:slashCommandId when `SlashCommandPresets.update()` returns a falsy value (null/undefined). The handler first checks ownership via `SlashCommandPresets.get()` (which passes, returning ownsPreset), then calls update — if the update method returns null, line 1363 sends 422 Unprocessable Entity. This indicates the preset was found but the update operation could not produce a valid result, a semantic mismatch rather than a not-found (404) or server error (500).","triggerScenarios":"The preset exists at the ownership check (line 1346-1351) but the subsequent `SlashCommandPresets.update(Number(slashCommandId), updates)` returns null. This can happen in a race condition where the row is deleted between the get and update calls, or the update method internally validates and rejects the new values (e.g., duplicate command, constraint violation) returning null instead of throwing.","commonSituations":"Two concurrent requests update or delete the same preset. The update payload contains a command that passes the system-command collision check (line 1338) but violates a unique constraint at the database level. A model-layer validation in SlashCommandPresets.update silently returns null on constraint failure.","solutions":["Check if another request or process deleted the preset between the ownership check and the update call.","Verify there are no unique constraints on the command column that would cause the update to silently fail.","Retry the request — if it was a transient race condition, the retry should succeed.","Inspect the SlashCommandPresets.update implementation to understand under what conditions it returns null (the model may swallow a DB error and return null instead)."],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// Validate the preset exists and is owned before updating\nasync function verifyPresetOwnership(slashCommandId) {\n  const res = await fetch(`/system/slash-command-presets/${slashCommandId}`, {\n    method: 'POST', // this is the update endpoint; use GET for listing\n  });\n  return res.ok;\n}","typeGuard":null,"tryCatchPattern":"try {\n  const res = await fetch(`/system/slash-command-presets/${id}`, {\n    method: 'POST',\n    body: JSON.stringify({ command, prompt, description }),\n  });\n  if (res.status === 422) {\n    // Update returned null — preset may have been deleted concurrently\n    // Retry once after re-fetching\n    console.warn('Preset update returned 422, retrying...');\n  } else if (res.status === 404) {\n    throw new Error('Preset not found or not owned by user');\n  }\n} catch (e) {\n  console.error('Preset update failed:', e.message);\n}","preventionTips":["Avoid concurrent updates to the same preset from multiple clients.","Handle 422 by re-fetching the preset list and retrying, since it may indicate a transient race condition.","Ensure the command value doesn't collide with existing presets' unique constraints."],"tags":["slash-command-presets","update","race-condition","validation"],"backgroundTag":null,"analyzedSha":"526360e320da9d1b36074be5ed64fe76e5bbfbbd","analyzedAt":"2026-08-13T01:45:47.170Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}