Skip to content
Closed
30 changes: 17 additions & 13 deletions src/youtube_extension/backend/cloud_ai_routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -228,8 +228,8 @@ async def get_provider_status():
)

except Exception as e:
logger.error(f"Failed to get provider status: {e}")
raise HTTPException(status_code=500, detail=f"Failed to get provider status: {str(e)}")
logger.error(f"Failed to get provider status: {e}", exc_info=True)
raise HTTPException(status_code=500, detail="Internal server error")


@router.post("/analyze/video", response_model=VideoAnalysisResponse)
Expand All @@ -255,20 +255,24 @@ async def analyze_video(request: VideoAnalysisRequest):
# Format and return response
return format_analysis_result(result)

except CloudAIError as e:
logger.error(f"Cloud AI analysis failed: {e}")
raise HTTPException(status_code=503, detail=f"AI analysis failed: {str(e)}")
except RateLimitError as e:
# Must precede CloudAIError: RateLimitError subclasses it, so catching
# the base first would shadow this handler and return a 503 instead.
logger.warning(f"Rate limit exceeded: {e}")
raise HTTPException(status_code=429, detail=f"Rate limit exceeded: {str(e)}")
Comment on lines 258 to 262
except ConfigurationError as e:
logger.error(f"Configuration error: {e}")
raise HTTPException(status_code=500, detail=f"Configuration error: {str(e)}")
# Must precede CloudAIError (same subclassing reason) so configuration
# failures reach this sanitized 500 rather than the dynamic 503 below.
logger.error(f"Configuration error: {e}", exc_info=True)
raise HTTPException(status_code=500, detail="Internal server error")
Comment thread
groupthinking marked this conversation as resolved.
except CloudAIError as e:
logger.error(f"Cloud AI analysis failed: {e}")
raise HTTPException(status_code=503, detail=f"AI analysis failed: {str(e)}")
except HTTPException:
raise
except Exception as e:
logger.error(f"Unexpected error during video analysis: {e}")
raise HTTPException(status_code=500, detail=f"Analysis failed: {str(e)}")
logger.error(f"Unexpected error during video analysis: {e}", exc_info=True)
raise HTTPException(status_code=500, detail="Internal server error")


@router.post("/analyze/batch")
Expand Down Expand Up @@ -300,8 +304,8 @@ async def analyze_batch_videos(request: BatchAnalysisRequest, background_tasks:
except HTTPException:
raise
except Exception as e:
logger.error(f"Failed to start batch analysis: {e}")
raise HTTPException(status_code=500, detail=f"Batch analysis failed: {str(e)}")
logger.error(f"Failed to start batch analysis: {e}", exc_info=True)
raise HTTPException(status_code=500, detail="Internal server error")


@router.post("/analyze/multi-provider", response_model=list[VideoAnalysisResponse])
Expand All @@ -324,8 +328,8 @@ async def analyze_video_multi_provider(request: VideoAnalysisRequest):
return formatted_results

except Exception as e:
logger.error(f"Multi-provider analysis failed: {e}")
raise HTTPException(status_code=500, detail=f"Multi-provider analysis failed: {str(e)}")
logger.error(f"Multi-provider analysis failed: {e}", exc_info=True)
raise HTTPException(status_code=500, detail="Internal server error")
Comment on lines 330 to +332


@router.get("/analysis-types")
Expand Down
27 changes: 12 additions & 15 deletions src/youtube_extension/backend/cloud_api_endpoints.py
Original file line number Diff line number Diff line change
Expand Up @@ -143,17 +143,10 @@ async def process_video_cloud(

except Exception as e:
error_msg = f"Cloud processing failed: {str(e)}"
logger.error(error_msg)
logger.error(error_msg, exc_info=True)

raise HTTPException(
status_code=500,
detail={
"error": "cloud_processing_failed",
"message": error_msg,
"video_url": request.video_url,
"timestamp": datetime.now(timezone.utc).isoformat()
}
)
# detail is a static string; error_msg (with the exception) is logged above only
raise HTTPException(status_code=500, detail="Internal server error")

@router.post("/api/v3/process-video-task")
async def process_video_task_handler(
Expand Down Expand Up @@ -216,7 +209,7 @@ async def process_video_task_handler(

except Exception as e:
error_msg = f"Task processing failed: {str(e)}"
logger.error(error_msg)
logger.error(error_msg, exc_info=True)

# Update state with error
try:
Expand All @@ -229,7 +222,8 @@ async def process_video_task_handler(
except Exception as state_error:
logger.error(f"Failed to update error state: {state_error}")

raise HTTPException(status_code=500, detail=error_msg)
# detail is a static string; error_msg (with the exception) is logged above only
raise HTTPException(status_code=500, detail="Internal server error")

@router.post("/api/v3/batch-process")
async def batch_process_videos_cloud(request: BatchCloudProcessingRequest):
Expand Down Expand Up @@ -260,9 +254,10 @@ async def batch_process_videos_cloud(request: BatchCloudProcessingRequest):
except HTTPException:
raise
except Exception as e:
logger.error(f"Unhandled error in batch_process_videos_cloud: {e}", exc_info=True)
raise HTTPException(
status_code=500,
detail=f"Batch processing failed: {str(e)}"
detail="Internal server error"
)

@router.get("/api/v3/videos/{video_id}/status", response_model=VideoStatusResponse)
Expand Down Expand Up @@ -293,9 +288,10 @@ async def get_video_status(video_id: str):
except HTTPException:
raise
except Exception as e:
logger.error(f"Unhandled error in get_video_status: {e}", exc_info=True)
raise HTTPException(
status_code=500,
detail=f"Error retrieving status: {str(e)}"
detail="Internal server error"
)

@router.get("/api/v3/videos/{video_id}/result")
Expand Down Expand Up @@ -330,9 +326,10 @@ async def get_video_result(video_id: str):
except HTTPException:
raise
except Exception as e:
logger.error(f"Unhandled error in get_video_result: {e}", exc_info=True)
raise HTTPException(
status_code=500,
detail=f"Error retrieving result: {str(e)}"
detail="Internal server error"
)

@router.get("/api/v3/queue/stats")
Expand Down
36 changes: 21 additions & 15 deletions src/youtube_extension/backend/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -444,22 +444,28 @@ async def value_error_handler(request, exc):

@app.exception_handler(Exception)
async def global_exception_handler(request, exc):
"""Global exception handler with enhanced error details"""
logger.error(f"Unhandled exception: {exc}", exc_info=True)

error_detail = {
"error": "Internal server error",
"detail": str(exc),
"timestamp": datetime.now().isoformat(),
"path": str(request.url) if hasattr(request, "url") else "unknown",
"version": "2.0.0",
"architecture": "service-oriented",
}

if hasattr(exc, "__class__"):
error_detail["error_type"] = exc.__class__.__name__
"""Global exception handler.

The full exception (type, message, traceback) and the request path are
logged server-side only. The client receives a static body so an unhandled
error cannot disclose internal details — exception text, exception type, or
the request URL (CWE-209).
"""
path = str(request.url) if hasattr(request, "url") else "unknown"
logger.error(
f"Unhandled exception on {path}: {exc}", exc_info=True
)

return JSONResponse(status_code=500, content=error_detail)
return JSONResponse(
status_code=500,
content={
"error": "Internal server error",
"detail": "Internal server error",
"timestamp": datetime.now().isoformat(),
"version": "2.0.0",
"architecture": "service-oriented",
},
)


# Application lifecycle events
Expand Down
34 changes: 19 additions & 15 deletions src/youtube_extension/backend/real_api_endpoints.py
Original file line number Diff line number Diff line change
Expand Up @@ -119,17 +119,10 @@ async def process_video_real_api(request: VideoProcessingRequest, background_tas

except Exception as e:
error_msg = f"Real API processing failed: {str(e)}"
logger.error(error_msg)
logger.error(error_msg, exc_info=True)

raise HTTPException(
status_code=500,
detail={
"error": "video_processing_failed",
"message": error_msg,
"video_url": request.video_url,
"timestamp": datetime.now(timezone.utc).isoformat()
}
)
# detail is a static string; error_msg (with the exception) is logged above only
raise HTTPException(status_code=500, detail="Internal server error")

@app.post("/api/v2/validate-video")
async def validate_video_url(request: VideoValidationRequest):
Expand All @@ -150,9 +143,10 @@ async def validate_video_url(request: VideoValidationRequest):
}

except Exception as e:
logger.error(f"Unhandled error in validate_video_url: {e}", exc_info=True)
raise HTTPException(
status_code=500,
detail=f"Validation failed: {str(e)}"
detail="Internal server error"
)

@app.post("/api/v2/batch-process")
Expand All @@ -176,10 +170,14 @@ async def batch_process_videos(request: BatchProcessingRequest):

return result

except HTTPException:
# Preserve explicit 4xx responses (e.g. the 400 batch-size guard above).
raise
except Exception as e:
logger.error(f"Unhandled error in batch_process_videos: {e}", exc_info=True)
raise HTTPException(
status_code=500,
detail=f"Batch processing failed: {str(e)}"
detail="Internal server error"
)

@app.get("/api/v2/videos/list")
Expand Down Expand Up @@ -252,9 +250,10 @@ async def get_video_analysis(video_id: str):
except HTTPException:
raise
except Exception as e:
logger.error(f"Unhandled error in get_video_analysis: {e}", exc_info=True)
raise HTTPException(
status_code=500,
detail=f"Error retrieving video analysis: {str(e)}"
detail="Internal server error"
)

@app.get("/api/v2/cost-dashboard")
Expand Down Expand Up @@ -384,9 +383,10 @@ async def clear_processing_cache():
}

except Exception as e:
logger.error(f"Unhandled error in clear_processing_cache: {e}", exc_info=True)
raise HTTPException(
status_code=500,
detail=f"Failed to clear cache: {str(e)}"
detail="Internal server error"
)

@app.post("/api/v2/search-videos")
Expand Down Expand Up @@ -431,10 +431,14 @@ async def search_youtube_videos(
"timestamp": datetime.now(timezone.utc).isoformat()
}

except HTTPException:
# Preserve explicit 4xx responses (e.g. the 400 max-results guard above).
raise
except Exception as e:
logger.error(f"Unhandled error in search_youtube_videos: {e}", exc_info=True)
raise HTTPException(
status_code=500,
detail=f"Search failed: {str(e)}"
detail="Internal server error"
)

logger.info("🚀 Real API endpoints setup complete")
Expand Down
Loading
Loading