{"record":{"id":"fd7896b490c1d8e9","repo":"Stirling-Tools/Stirling-PDF","slug":"operationname-operation-failed-error-respons","errorCode":null,"errorMessage":"${operationName} operation failed: ${error.response?.data || error.message}","messagePattern":"(.+?) operation failed: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"frontend/editor/src/core/utils/automationExecutor.ts","lineNumber":207,"sourceCode":"    // Execute based on tool type\n    if (config.toolType === ToolType.multiFile) {\n      return await executeMultiFileOperation(\n        config,\n        mergedParameters,\n        files,\n        filePrefix,\n      );\n    } else {\n      return await executeSingleFileOperation(\n        config,\n        mergedParameters,\n        files,\n        filePrefix,\n      );\n    }\n  } catch (error: any) {\n    console.error(`❌ ${operationName} failed:`, error);\n    throw new Error(\n      `${operationName} operation failed: ${error.response?.data || error.message}`,\n      {\n        cause: error,\n      },\n    );\n  }\n};\n\n/**\n * Execute an entire automation sequence\n */\nexport const executeAutomationSequence = async (\n  automation: any,\n  initialFiles: File[],\n  toolRegistry: ToolRegistry,\n  onStepStart?: (stepIndex: number, operationName: string) => void,\n  onStepComplete?: (stepIndex: number, resultFiles: File[]) => void,\n  onStepError?: (stepIndex: number, error: string) => void,","sourceCodeStart":189,"sourceCodeEnd":225,"githubUrl":"https://github.com/Stirling-Tools/Stirling-PDF/blob/9ef20dcab80b85041912f045e17a6aea1d08f969/frontend/editor/src/core/utils/automationExecutor.ts#L189-L225","documentation":"A catch-all wrapper thrown by executeToolOperationWithPrefix when any error escapes the tool execution body (single-file, multi-file, or customProcessor path). It re-throws with the operationName prefixed and the underlying cause attached via { cause: error }, preferring error.response?.data (Axios-style backend error body) over error.message. This is the error a caller of the executor actually sees for any backend or processing failure.","triggerScenarios":"The backend POST returns a non-2xx (Axios rejects, error.response.data holds the server message). A network failure or timeout occurs (no response object, message is the network error). A customProcessor throws synchronously or its internal processing rejects. The processMultiFileResponse/zip extraction step fails downstream.","commonSituations":"Backend is down or the endpoint returned 400/500 (e.g. malformed params, unsupported file type, server exception). The user's session expired and the API returned 401/403. A large file caused a gateway timeout. The backend PDF operation threw because the input file was corrupt or password-protected.","solutions":["Inspect error.cause for the original error object; the wrapper preserves it.","If error.response.data is present, read the backend's message — it usually pinpoints the bad parameter or file.","Check browser DevTools Network tab for the failing POST to see status code and response body.","If it is a transient network/timeout issue, consider retrying with backoff for idempotent operations.","Validate file types and parameters against the tool's requirements before submitting."],"exampleFix":"// before — caller does not inspect cause\ncatch (e) { show(e.message); }\n// after — unwrap the real error\ncatch (e) {\n  const detail = e.cause?.response?.data ?? e.cause?.message ?? e.message;\n  show(`${operationName} failed: ${detail}`);\n}","handlingStrategy":"try-catch","validationCode":"// Pre-flight: ensure files are non-empty and of expected type before submitting.\nfunction validateToolInputs(op: string, params: any, files: File[]): string | null {\n  if (!files.length) return 'No files provided.';\n  if (files.some(f => f.size === 0)) return 'One or more files are empty.';\n  return null;\n}\nconst issue = validateToolInputs(op, params, files);\nif (issue) { showUser(issue); return; }","typeGuard":"function isAxiosError(e: unknown): e is { response?: { status: number; data: any }; message: string } {\n  return !!e && typeof e === 'object' && 'response' in e;\n}","tryCatchPattern":"try {\n  await executeToolOperation(op, params, files, registry);\n} catch (e) {\n  const err = e as Error & { cause?: any };\n  const cause = err.cause;\n  const detail = cause?.response?.data ?? cause?.message ?? err.message;\n  const status = cause?.response?.status;\n  if (status === 401 || status === 403) showUser('Session expired. Please log in again.');\n  else if (status && status >= 500) showUser('Server error. Please try again later.');\n  else showUser(`${op} failed: ${detail}`);\n}","preventionTips":["Always read error.cause for the underlying error object.","Validate file types and sizes before submission to avoid backend 400s.","Handle 401/403 specifically with a re-auth prompt.","For idempotent operations, implement a bounded retry on network/5xx errors."],"tags":["automation","backend","network","axios","wrapper"],"backgroundTag":null,"analyzedSha":"9ef20dcab80b85041912f045e17a6aea1d08f969","analyzedAt":"2026-08-13T22:11:39.827Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}