Volver a la wiki

Incidente s68 — Eventos Zoho Calendar no se borraban (ETAG_MISSING)

Resumen

La noche del 17-05-2026 (sesión s68) se detectó que al cerrar una tarea en CreaRack, el evento correspondiente seguía visible en Zoho Calendar aunque la fila en D1 había sido borrada correctamente. La causa raíz fue la ausencia del header etag en la petición DELETE al API de Zoho Calendar.


Síntoma

Respuesta exacta de Zoho:

{"error_code": "ETAG_MISSING", "message": "ETAG_MISSING"}

Causa raíz

La Zoho Calendar API implementa concurrencia optimista vía ETag: cada recurso tiene una versión (etag) que debe enviarse en el header etag de todas las operaciones de escritura (DELETE, PUT). Sin él, el servidor rechaza la petición con HTTP 400.

El código anterior en deleteEventsByType y en el bloque de onTaskDeleted omitía este header:

// ANTES (bug)
await zohoFetch(env, member, url, { method: 'DELETE' });

Fix aplicado (commit e779e6a)

Se introdujo la función fetchEventEtag que realiza un GET previo al evento para obtener el ETag actual, y luego lo incluye en el DELETE:

// DESPUÉS (fix)
const etag = await fetchEventEtag(env, member, row.calendar_uid, row.zoho_event_uid);
if (!etag) {
  console.warn(`[task-zoho-auto] DELETE ${row.zoho_event_uid}: no etag (ya borrado en Zoho)`);
  continue; // skip — evento ya no existe
}
await zohoFetch(env, member, url, { method: 'DELETE', headers: { etag } });

El patrón también cubre el caso de evento ya borrado en Zoho: si el GET devuelve 404 (!res.ok), fetchEventEtag retorna null y el DELETE se omite, evitando errores espurios.


Impacto

DimensiónDetalle
SeveridadMedia — datos inconsistentes entre D1 y Zoho Calendar (no bloqueo de prod)
VentanaIndeterminada (bug presente antes de s68, detectado esa noche)
AfectadosTodos los usuarios con integración Zoho Calendar activa al cerrar tareas
Pérdida de datosNo — los eventos sólo quedaban “huérfanos” en Zoho; ningún dato interno perdido

Acciones tomadas

  1. Diagnóstico vía endpoint de debug que retornó el body ETAG_MISSING.
  2. Fix en functions/_lib/task-zoho-auto.ts — patrón GET → ETag → DELETE.
  3. Commit directo a main e779e6a por @Esquembri, co-autorado con Claude Opus 4.7.
  4. Limpieza manual de eventos huérfanos en Zoho (si necesaria, fuera de scope del commit).

Lecciones aprendidas


Véase también

Subir