Discourse AI: una solicitud de Gemini bloqueada por promptFeedback.blockReason se trata como respuesta vacía y nunca se traduce

Descripción

Cuando la API de Gemini de Google rechaza una solicitud con promptFeedback.blockReason, Discourse AI trata la respuesta como una respuesta exitosa pero vacía. En la traducción por IA, esto tiene dos efectos: el tema o la publicación nunca recibe un idioma detectado, por lo que nunca se traduce, y el relleno (backfill) vuelve a enviar la misma solicitud bloqueada en ejecuciones posteriores. Nada indica al administrador que se produjo un bloqueo.

Observado en un sitio autoalojado que ejecuta release/2026.7 (2026.7.3, commit f1caa6321287f918644fba9ff8943579fdcf027a) con el plugin discourse-ai integrado. La solicitud fue la detección de idioma de un título de tema, utilizando el agente detector de idioma integrado en gemini-3.5-flash-lite. El título era una oración corta e inofensiva en sueco. El mismo título fue traducido por gemini-3.8-flash sin bloqueo.

Google respondió con HTTP 200 y un único evento de flujo sin candidatos:

data: {"promptFeedback": {"blockReason": "PROHIBITED_CONTENT"},"usageMetadata": {"promptTokenCount": 417,"totalTokenCount": 417,"promptTokensDetails": [{"modality": "TEXT","tokenCount": 417}],"serviceTier": "standard"},"modelVersion": "gemini-3.5-flash-lite","responseId": "..."}

La solicitud ya lleva BLOCK_NONE para las cuatro categorías de seguridad que Discourse AI establece, por lo que este bloqueo no es uno de los que influyen en esas configuraciones. El registro de auditoría registra response_status 200.

Causa raíz

  1. DiscourseAi::Completions::Endpoints::Gemini#decode_chunk solo lee candidates de cada evento de flujo. promptFeedback nunca se inspecciona, por lo que una solicitud bloqueada produce un resultado vacío sin error.
  2. DiscourseAi::Translation::LanguageDetector#detect devuelve nil cuando la respuesta no coincide con su patrón de etiqueta de idioma, que es el caso para una respuesta vacía. El tema o la publicación mantiene locale como NULL.
  3. Jobs::TopicsLocaleDetectionBackfill selecciona temas con locale NULL en cada ejecución y no tiene límite de intentos, por lo que, al leer el código, la solicitud bloqueada se repite cada cinco minutos durante el tiempo que el tema esté en la ventana de relleno. Las publicaciones están limitadas a dos intentos de detección al día por la cuota de relocalización, y se reintentan cada día.
  4. Los candidatos de traducción requieren un locale detectado, por lo que el elemento nunca se traduce.

El mismo código está presente en main a fecha del 2026-10-03.

Solución sugerida

  1. Detectar promptFeedback.blockReason en el punto de entrada de Gemini y lanzar o registrar un error distinto y visible que nombre la razón.
  2. Registrar el fallo contra el tema o la publicación para que el relleno deje de repetir una solicitud que será bloqueada nuevamente, o aplicar un límite de intentos a la detección de temas como ya existe para las publicaciones.
  3. Mostrar los elementos bloqueados en la página de administración de traducción, para que un administrador pueda establecer el idioma manualmente.

Reproducir

El bloqueo depende del filtro de Google y no se puede forzar con una entrada conocida. Las llamadas afectadas se pueden encontrar en el registro de auditoría:

SELECT id, created_at, language_model, post_id, topic_id, response_status
FROM ai_api_audit_logs
WHERE feature_name = 'translation'
  AND raw_response_payload LIKE '%blockReason%'
ORDER BY created_at

Solución temporal

Establecer el idioma del tema manualmente permite que la traducción continúe. En este sitio, el modelo de traducción no bloqueó el mismo texto.

1 me gusta

gracias por el informe @Sailor :+1:

se solucionará con FIX: Handle Gemini errors and blocked prompts reported in successful responses - Pull Request #44262 - discourse/discourse - GitHub

1 me gusta

Gracias por la rápida solución. Una parte de este informe sigue abierta después de #44262, al menos según muestra la diferencia de código.

Con el cambio, se registra una detección bloqueada y, en el caso de los temas, se limita a dos intentos al día. El elemento en sí termina sin un idioma asignado, por lo que nunca se traduce y sigue contándose como pendiente de detección indefinidamente. Nada en la interfaz de administración muestra cuáles son estos elementos.

Durante una sola ejecución de backfill de aproximadamente 6.700 publicaciones y sus temas en este sitio, surgieron tres casos, todos en gemini-3.5-flash-lite con PROHIBITED_CONTENT y todos inofensivos: un título de tema, una publicación de una sola frase y una publicación que consistía en un único enlace.

Dos posibles soluciones:

  1. Un idioma de respaldo cuando la detección esté bloqueada, por ejemplo, el idioma de la interfaz del autor o, en el caso de una respuesta, el idioma de su tema. En el único caso aquí donde el idioma se estableció manualmente y el elemento se dejó al backfill, el modelo de traducción lo tradujo sin objeción.
  2. Si no, una lista o recuento de elementos cuya detección fue bloqueada en la página de administración de traducción, para que el idioma pueda establecerse manualmente.