diff --git a/src/core/main.py b/src/core/main.py index 9c9019438..8abb08682 100644 --- a/src/core/main.py +++ b/src/core/main.py @@ -2126,19 +2126,56 @@ def _sync_creatives_impl( f"url={bool(data.get('url'))}, " f"width={data.get('width')}, " f"height={data.get('height')}, " - f"variants={len(preview_result.get('previews', [])) if preview_result else 0}" + f"variants={len(preview_result.get('previews', []))}" ) + else: + # Preview generation failed for update - creative is invalid + error_msg = f"Creative validation failed: preview_creative returned no previews for update of {existing_creative.creative_id}" + logger.error(f"[sync_creatives] {error_msg}") + failed_creatives.append( + { + "creative_id": existing_creative.creative_id, + "error": error_msg, + "format": creative_format, + } + ) + failed_count += 1 + results.append( + SyncCreativeResult( + creative_id=existing_creative.creative_id, + action="failed", + errors=[error_msg], + ) + ) + continue # Skip this creative update except Exception as validation_error: - # Creative agent validation failed for update - log warning but continue - # This allows updates even if creative agent is down - error_msg = f"Creative agent validation failed: {str(validation_error)}" - logger.warning( - f"[sync_creatives] {error_msg} for update of {existing_creative.creative_id} - continuing with update", + # Creative agent validation failed for update (network error, agent down, etc.) + # Do NOT update the creative - it needs validation before acceptance + error_msg = ( + f"Creative agent unreachable or validation error: {str(validation_error)}. " + f"Retry recommended - creative agent may be temporarily unavailable." + ) + logger.error( + f"[sync_creatives] {error_msg} for update of {existing_creative.creative_id}", exc_info=True, ) - # Note: We continue instead of failing to allow graceful degradation - # when creative agent is unavailable + failed_creatives.append( + { + "creative_id": existing_creative.creative_id, + "error": error_msg, + "format": creative_format, + } + ) + failed_count += 1 + results.append( + SyncCreativeResult( + creative_id=existing_creative.creative_id, + action="failed", + errors=[error_msg], + ) + ) + continue # Skip this creative update # In full upsert, consider all fields as changed changes.extend(["url", "click_url", "width", "height", "duration"]) @@ -2389,24 +2426,61 @@ def _sync_creatives_impl( if dimensions.get("duration"): data["duration"] = dimensions["duration"] - logger.info( - f"[sync_creatives] Preview data populated: " - f"url={bool(data.get('url'))}, " - f"width={data.get('width')}, " - f"height={data.get('height')}, " - f"variants={len(preview_result.get('previews', [])) if preview_result else 0}" - ) + logger.info( + f"[sync_creatives] Preview data populated: " + f"url={bool(data.get('url'))}, " + f"width={data.get('width')}, " + f"height={data.get('height')}, " + f"variants={len(preview_result.get('previews', []))}" + ) + else: + # Preview generation failed - creative is invalid + error_msg = f"Creative validation failed: preview_creative returned no previews for {creative_id}" + logger.error(f"[sync_creatives] {error_msg}") + failed_creatives.append( + { + "creative_id": creative_id, + "error": error_msg, + "format": creative_format, + } + ) + failed_count += 1 + results.append( + SyncCreativeResult( + creative_id=creative_id, + action="failed", + errors=[error_msg], + ) + ) + continue # Skip this creative except Exception as validation_error: - # Creative agent validation failed - log warning but continue - # This allows creatives to be stored even if creative agent is down - error_msg = f"Creative agent validation failed: {str(validation_error)}" - logger.warning( - f"[sync_creatives] {error_msg} - continuing with creative storage", + # Creative agent validation failed (network error, agent down, etc.) + # Do NOT store the creative - it needs validation before acceptance + error_msg = ( + f"Creative agent unreachable or validation error: {str(validation_error)}. " + f"Retry recommended - creative agent may be temporarily unavailable." + ) + logger.error( + f"[sync_creatives] {error_msg} - rejecting creative {creative_id}", exc_info=True, ) - # Note: We continue instead of failing to allow graceful degradation - # when creative agent is unavailable + failed_creatives.append( + { + "creative_id": creative_id, + "error": error_msg, + "format": creative_format, + } + ) + failed_count += 1 + results.append( + SyncCreativeResult( + creative_id=creative_id, + action="failed", + errors=[error_msg], + ) + ) + continue # Skip storing this creative # Determine creative status based on approval mode diff --git a/templates/creative_management.html b/templates/creative_management.html index 027b4c450..297681078 100644 --- a/templates/creative_management.html +++ b/templates/creative_management.html @@ -392,7 +392,7 @@
No preview available for this creative.
-Creative data: ${JSON.stringify(creativeData || {}, null, 2)}
+This creative doesn't have preview data yet.
+${JSON.stringify(creativeData || {}, null, 2)}
+