{"record":{"id":"ef53a3bd8c140087","repo":"lfnovo/open-notebook","slug":"error-executing-transformation-str-e","errorCode":null,"errorMessage":"Error executing transformation: {str(e)}","messagePattern":"Error executing transformation: (.+?)","errorType":"http","errorClass":"HTTPException","httpStatus":500,"severity":"error","filePath":"api/routers/transformations.py","lineNumber":134,"sourceCode":"                input_text=execute_request.input_text,\n                transformation=transformation,\n            ),\n            config=dict(configurable={\"model_id\": model_id}),\n        )\n\n        return TransformationExecuteResponse(\n            output=result[\"output\"],\n            transformation_id=execute_request.transformation_id,\n            model_id=model_id,\n        )\n\n    except HTTPException:\n        raise\n    except OpenNotebookError:\n        raise  # Let global exception handlers return proper status codes\n    except Exception as e:\n        logger.error(f\"Error executing transformation: {str(e)}\")\n        raise HTTPException(\n            status_code=500, detail=f\"Error executing transformation: {str(e)}\"\n        )\n\n\n@router.get(\"/transformations/default-prompt\", response_model=DefaultPromptResponse)\nasync def get_default_prompt():\n    \"\"\"Get the default transformation prompt.\"\"\"\n    try:\n        default_prompts: DefaultPrompts = await DefaultPrompts.get_instance()  # type: ignore[assignment]\n\n        return DefaultPromptResponse(\n            transformation_instructions=default_prompts.transformation_instructions\n            or \"\"\n        )\n    except HTTPException:\n        raise\n    except OpenNotebookError:\n        raise","sourceCodeStart":116,"sourceCodeEnd":152,"githubUrl":"https://github.com/lfnovo/open-notebook/blob/a7de90d38aaf18ee85fd661854d35c11e44613e2/api/routers/transformations.py#L116-L152","documentation":"Generic 500 raised by the POST /transformations/execute endpoint when the transformation graph (LangGraph) invocation fails with an unexpected exception. The endpoint validates the transformation and model first (404s), so a 500 here almost always originates inside transformation_graph.ainvoke — e.g. the AI provider call, prompt rendering, or output parsing.","triggerScenarios":"POST /api/transformations/execute with a valid transformation_id and model_id where the underlying LLM provider errors (bad API key, rate limit, model name not available on the provider), or where the transformation's prompt produces unparseable output in the graph.","commonSituations":"Provider API key missing/expired in environment, provider quota exhausted, transformation bound to a model whose provider credentials were rotated, or a malformed transformation prompt that crashes the graph node.","solutions":["Check the API server logs — the original exception message is logged via logger.error right before the 500 is raised","Verify the model's provider credentials (API key env var) and that the model name is valid for that provider","Test the same transformation with a small input text and the default model via /transformations/execute to isolate prompt vs provider issues","If the provider is rate limiting, retry after backoff or switch the transformation to another model_id"],"exampleFix":"// before\nresult = await client.post('/transformations/execute', json=req)\nresult.raise_for_status()\n// after\nresult = await client.post('/transformations/execute', json=req)\nif result.status_code == 500:\n    detail = result.json().get('detail', '')\n    if 'rate limit' in detail.lower():\n        await asyncio.sleep(30)\n        result = await client.post('/transformations/execute', json=req)\n    else:\n        raise RuntimeError(f'Transformation failed: {detail}')","handlingStrategy":"try-catch","validationCode":"resp = await client.get(f'/transformations/{req[\"transformation_id\"]}')\nassert resp.status_code == 200, 'transformation missing'\nif req.get('model_id'):\n    assert (await client.get(f'/models/{req[\"model_id\"]}')).status_code == 200, 'model missing'","typeGuard":null,"tryCatchPattern":"try:\n    out = await client.post('/transformations/execute', json=req)\nexcept httpx.TransportError:\n    # network-level failure, safe to retry\n    raise\nif out.status_code >= 500:\n    detail = out.json().get('detail', '')\n    if 'rate' in detail.lower():\n        await retry_with_backoff(req)\n    else:\n        raise RuntimeError(detail)","preventionTips":["Validate transformation_id and model_id exist via GET before executing","Keep provider API keys configured and rotated in the Models section","Surface the 500 detail message to logs — it contains the root cause"],"tags":["fastapi","http-500","transformation","langgraph","llm-provider"],"backgroundTag":"llm-provider-request-failed","analyzedSha":"a7de90d38aaf18ee85fd661854d35c11e44613e2","analyzedAt":"2026-08-27T02:39:58.166Z","schemaVersion":2},"datasetVersion":"2026-08-27T03:17:27.898Z"}