{"record":{"id":"eedc612347d5c441","repo":"Mintplex-Labs/anything-llm","slug":"res-error-failed-to-save-flow","errorCode":null,"errorMessage":"${res.error || \"Failed to save flow\"}","messagePattern":"\\$\\{res\\.error \\|\\| \"Failed to save flow\"\\}","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"frontend/src/models/agentFlows.js","lineNumber":22,"sourceCode":"const AgentFlows = {\n  /**\n   * Save a flow configuration\n   * @param {string} name - Display name of the flow\n   * @param {object} config - The configuration object for the flow\n   * @param {string} [uuid] - Optional UUID for updating existing flow\n   * @returns {Promise<{success: boolean, error: string | null, flow: {name: string, config: object, uuid: string} | null}>}\n   */\n  saveFlow: async (name, config, uuid = null) => {\n    return await fetch(`${API_BASE}/agent-flows/save`, {\n      method: \"POST\",\n      headers: {\n        ...baseHeaders(),\n        \"Content-Type\": \"application/json\",\n      },\n      body: JSON.stringify({ name, config, uuid }),\n    })\n      .then((res) => {\n        if (!res.ok) throw new Error(res.error || \"Failed to save flow\");\n        return res;\n      })\n      .then((res) => res.json())\n      .catch((e) => ({\n        success: false,\n        error: e.message,\n        flow: null,\n      }));\n  },\n\n  /**\n   * List all available flows in the system\n   * @returns {Promise<{success: boolean, error: string | null, flows: Array<{name: string, uuid: string, description: string, steps: Array}>}>}\n   */\n  listFlows: async () => {\n    return await fetch(`${API_BASE}/agent-flows/list`, {\n      method: \"GET\",\n      headers: baseHeaders(),","sourceCodeStart":4,"sourceCodeEnd":40,"githubUrl":"https://github.com/Mintplex-Labs/anything-llm/blob/526360e320da9d1b36074be5ed64fe76e5bbfbbd/frontend/src/models/agentFlows.js#L4-L40","documentation":"Thrown from `saveFlow` on a non-ok `POST /api/agent-flows/save`. NOTE: `res.error` is read off the fetch `Response` object, which has NO `.error` property — `res.error` is always `undefined`, so this expression ALWAYS falls through to the literal 'Failed to save flow', discarding any server-provided error message. This is a defect; compare with communityHub models that `await res.json()` first then read `response.error`.","triggerScenarios":"Any non-2xx from the save endpoint: invalid flow config, duplicate name/uuid, backend validation failure, 401/403, or 500. In every case the user sees only 'Failed to save flow', not the real reason.","commonSituations":"User saves a flow with a name collision or malformed config; session expires; backend schema changes; debugging is hard because the helpful server message is dropped.","solutions":["Fix the defect: parse the JSON body first, then read `response.error` (mirroring communityHub.js).","While debugging, check the browser network tab — the response body carries the real error.","On 401 re-authenticate; on 400 fix the payload per the server message.","Add a test asserting the server error message propagates to the thrown Error."],"exampleFix":"// before\n.then((res) => {\n  if (!res.ok) throw new Error(res.error || 'Failed to save flow'); // res.error is always undefined\n  return res;\n})\n\n// after — read the JSON body so the server's error survives\n.then(async (res) => {\n  const response = await res.json();\n  if (!res.ok) throw new Error(response?.error || `Failed to save flow (HTTP ${res.status})`);\n  return response;\n})","handlingStrategy":"try-catch","validationCode":"// The bug is in the model. Caller-side, validate inputs and inspect network:\nfunction validateFlowPayload(name, config) {\n  if (typeof name !== 'string' || !name.trim()) throw new Error('Flow name is required');\n  if (!config || typeof config !== 'object') throw new Error('Flow config is required');\n}","typeGuard":"function isFlowPayloadValid(name, config) {\n  return typeof name === 'string' && name.trim().length > 0 && !!config && typeof config === 'object';\n}","tryCatchPattern":"const { success, error, flow } = await AgentFlows.saveFlow(name, config, uuid);\nif (!success) {\n  // NOTE: error is the generic 'Failed to save flow' until the model bug is fixed.\n  // Inspect the network tab for the server's actual message.\n  showToast(error);\n}","preventionTips":["Fix the model: read `response.error` from the parsed JSON body (see exampleFix).","Validate name + config before posting.","Add a test asserting the server error message propagates."],"tags":["frontend","agent-flows","fetch","bug","network"],"backgroundTag":null,"analyzedSha":"526360e320da9d1b36074be5ed64fe76e5bbfbbd","analyzedAt":"2026-08-13T01:45:47.170Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}