Claude Code para corrección de importación/exportación de datos: define reglas de validación, formatos de error consistentes y pruebas fuzz para importaciones CSV/JSON y reduce tickets por casos límite.

Las importaciones rara vez fallan porque el código esté “mal”. Fallan porque los datos reales son desordenados, inconsistentes y los genera gente que nunca vio tus supuestos.
Los problemas con CSV suelen ser de forma y formato. Los problemas con JSON suelen ser de significado y tipos. Ambos pueden romperse de maneras que parecen menores pero generan resultados confusos.
Estos problemas aparecen una y otra vez en tickets de soporte:
"00123" se convierte en 123, true/false se convierte en "yes"/"no")La corrección no es solo “¿se importó?”. Hay que decidir qué resultados están permitidos, porque los usuarios notan los errores silenciosos más que los fallos ruidosos.
La mayoría de los equipos pueden acordar tres resultados:
Los casos límite se convierten en reprocesos cuando la gente no puede saber qué salió mal ni cómo arreglarlo rápido. Un escenario común: un cliente sube un CSV de 5.000 filas, el importador dice “Formato inválido”, y vuelve a intentar tres veces con ediciones aleatorias. Eso genera múltiples tickets más alguien de tu equipo intentando reproducir el archivo localmente.
Pon objetivos que reduzcan el ciclo: menos reintentos, arreglos más rápidos, resultados predecibles. Antes de escribir reglas, decide qué significa “parcial” (y si lo permites), cómo informarás problemas a nivel de fila y qué debe hacer el usuario después (editar el archivo, mapear campos o exportar una versión corregida). Si usas una plataforma de generación de código como Koder.ai (koder.ai) para generar validadores y pruebas rápidamente, el contrato de importación sigue siendo lo que mantiene ese comportamiento consistente a medida que el producto evoluciona.
Antes de escribir una sola regla de validación, decide qué significa “entrada válida” para tu producto. La mayoría de los errores de importación son expectativas desajustadas entre lo que los usuarios suben y lo que tu sistema asume en silencio.
Empieza por los formatos y sé explícito. “CSV” puede significar coma o punto y coma, una fila de encabezado o no, UTF-8 o “lo que Excel produjo”. Para JSON, decide si aceptas un solo objeto, un array de registros o JSON Lines (un objeto JSON por línea). Si aceptas JSON anidado, define qué rutas lees y cuáles ignoras.
Luego fija el contrato por campo. Para cada campo, decide si es requerido, opcional u opcional con un valor por defecto. Los valores por defecto son parte del contrato, no un detalle de implementación. Si country falta, ¿por defecto dejas vacío, eliges un país específico o rechazas la fila?
El comportamiento de parsing es donde las importaciones “tolerantes” crean problemas a largo plazo. Decide desde el principio cuán estrictos son con recortar espacios, normalizar mayúsculas/minúsculas y aceptar variantes como "yes"/"true"/"1". La tolerancia está bien si es predecible y está documentada.
Los duplicados son otra decisión del contrato que afecta la corrección y la confianza. Define qué cuenta como duplicado (mismo email, mismo external_id, o la misma combinación de campos), dónde lo detectas (dentro del archivo, contra los datos existentes o ambos) y qué haces cuando ocurre (mantener el primero, mantener el último, fusionar o rechazar).
Una lista de verificación del contrato que puedes pegar en una especificación:
Ejemplo: importar “customers.” Si el email es la clave única, decide si " [email protected] " equivale a "[email protected]", si el email puede faltar cuando existe external_id, y si los duplicados dentro del archivo deben rechazarse incluso si la base de datos no tiene coincidencias. Una vez fijado este contrato, el comportamiento consistente en UI y API es mucho más fácil, ya sea que lo implementes en Koder.ai o en otro lado.
Las importaciones desordenadas a menudo empiezan con una única función gigante validate(). Un enfoque más limpio es usar reglas por capas con nombres claros y funciones pequeñas. Eso facilita revisar cambios y escribir pruebas.
Empieza con reglas a nivel de campo: verifican que un solo valor pase o falle por sí mismo (tipo, rango, longitud, valores permitidos, regex). Mantenlas aburridas y predecibles. Ejemplos: email coincide con un patrón básico de correo, age es un entero entre 0 y 120, status es uno de active|paused|deleted.
Agrega reglas entre campos solo donde importen. Estas verificaciones dependen de varios campos, y ahí se esconden bugs. Ejemplos clásicos: startDate debe ser anterior a endDate, o total debe ser subtotal + tax - discount. Escribe estas reglas para que puedan señalar campos específicos, no solo “registro inválido”.
Separa reglas a nivel de registro de reglas a nivel de archivo. Una regla a nivel de registro revisa una fila (CSV) o un objeto (JSON). Una regla a nivel de archivo revisa la subida completa: que existan encabezados requeridos, que una clave única no se repita entre filas, que la cuenta de columnas coincida con la esperada, o que el archivo declare una versión soportada.
La normalización debe ser explícita, no “mágica”. Decide qué normalizas antes de validar y documéntalo. Ejemplos comunes incluyen recortar espacios, normalización Unicode (para que caracteres visualmente idénticos comparen igual) y formatear teléfonos a un formato de almacenamiento consistente.
Una estructura que se mantiene legible:
Versiona tus reglas. Pon un schemaVersion (o “perfil” de importación) en el archivo o en la petición API. Cuando cambies lo que significa “válido”, aún podrás reimportar exportaciones antiguas usando la versión anterior. Esa decisión evita muchos tickets de “antes funcionaba”.
Un buen importador falla de forma útil. Los errores vagos llevan a reintentos aleatorios y trabajo de soporte evitable. Un formato de error claro ayuda a los usuarios a arreglar el archivo rápido y te ayuda a mejorar la validación sin romper clientes.
Empieza por una forma de objeto de error estable y mantenla consistente para CSV y JSON. Puedes usar Claude Code para proponer un esquema y algunos ejemplos realistas, y luego fijarlo como parte del contrato de importación.
Trata cada error como un pequeño registro con campos que no cambian. El mensaje puede evolucionar, pero el código y la ubicación deben permanecer estables.
code: un identificador corto y estable como REQUIRED_MISSING o INVALID_DATEmessage: una frase amigable para mostrar en la UIpath: dónde está el problema (puntero JSON tipo /customer/email, o un nombre de columna como email)row o line: para CSV, incluye el número de fila basado en 1 (y opcionalmente la línea original)severity: al menos error y warningHaz los errores accionables. Incluye qué esperabas y qué viste, y cuando sea posible muestra un ejemplo que pase. Por ejemplo: esperado YYYY-MM-DD, recibido 03/12/24.
Aunque devuelvas una lista plana, incluye suficientes datos para agrupar errores por fila y por campo. Muchas UIs quieren “Fila 12 tiene 3 problemas” y luego resaltar cada columna. Los equipos de soporte gustan de agrupar porque los patrones se hacen evidentes (por ejemplo, todas las filas faltan country).
Una respuesta compacta podría verse así:
{
"importId": "imp_123",
"status": "failed",
"errors": [
{
"code": "INVALID_DATE",
"message": "Signup date must be in YYYY-MM-DD.",
"path": "signup_date",
"row": 12,
"severity": "error",
"expected": "YYYY-MM-DD",
"actual": "03/12/24"
},
{
"code": "UNKNOWN_FIELD",
"message": "Column 'fav_colour' is not recognized.",
"path": "fav_colour",
"row": 1,
"severity": "warning"
}
]
}
Planifica la localización sin cambiar los códigos de error. Mantén code neutral al idioma y durable, y trata message como texto reemplazable. Si luego añades messageKey o mensajes traducidos, los clientes viejos aún pueden confiar en los mismos códigos para filtrar, agrupar y hacer analítica.
Para evitar “importaciones misteriosas”, la respuesta de tu API debe contestar dos preguntas: qué pasó y qué debe hacer el usuario después.
Incluso cuando hay errores, devuelve un resumen consistente para que la UI y las herramientas de soporte manejen cada importación de la misma manera.
Incluye:
created, updated, skipped, failedtotalRows (o totalRecords para JSON)mode (por ejemplo: "createOnly", "upsert" o "updateOnly")startedAt y finishedAtcorrelationId que soporte pueda pedirEse correlationId vale la pena. Cuando alguien reporta “no se importó”, puedes encontrar la ejecución exacta y el reporte de errores sin adivinar.
No vuelques 10.000 errores de fila en la respuesta. Devuelve una muestra pequeña (por ejemplo 20) que muestre el patrón y ofrece una vía separada para recuperar el reporte completo si es necesario.
Haz cada error específico y estable:
Ejemplo de forma de respuesta (éxito con algunos fallos de fila):
{
"importId": "imp_01HZY...",
"correlationId": "c_9f1f2c2a",
"status": "completed_with_errors",
"summary": {
"totalRows": 1200,
"created": 950,
"updated": 200,
"skipped": 10,
"failed": 40
},
"errorsSample": [
{
"row": 17,
"field": "email",
"code": "invalid_format",
"message": "Email must contain '@'.",
"value": "maria.example.com"
}
],
"report": {
"hasMore": true,
"nextPageToken": "p_002"
},
"next": {
"suggestedAction": "review_errors"
}
}
Fíjate en el campo next. Incluso una carga mínima de éxito debe ayudar al producto a avanzar: mostrar una pantalla de revisión, ofrecer un reintento o abrir la colección importada.
La gente reintenta. Las redes fallan. Si el mismo archivo se importa dos veces, quieres resultados previsibles.
Sé explícito sobre idempotencia: acepta una idempotencyKey (o calcula el hash del archivo) y devuelve el mismo importId si la petición es un duplicado. Si tu modo es upsert, define la regla de coincidencia (por ejemplo, “email es la clave única”). Si es solo crear, devuelve “skipped” para duplicados, no “created again.”
Si la petición entera es inválida (auth mala, content type incorrecto, archivo ilegible), falla rápido y devuelve status: "rejected" con una lista corta de errores. Si el archivo es válido pero tiene problemas a nivel de fila, trátalo como un trabajo completado con failed > 0 para que los usuarios puedan arreglar y volver a subir sin perder el resumen.
Un hábito útil: hacer que el modelo escriba el contrato en un formato estructurado, no en prosa. “Párrafos útiles” a menudo omiten detalles como reglas de recorte, valores por defecto y si una celda vacía significa “faltante” o “vacía”.
Usa un prompt que fuerce una tabla que una persona pueda revisar rápidamente y que un desarrollador pueda convertir en código. Pide la regla de cada campo, ejemplos de éxito y fracaso, y una nota explícita para cualquier ambigüedad (por ejemplo, cadena vacía vs null).
You are helping design an importer for CSV and JSON.
Output a Markdown table with columns:
Field | Type | Required? | Normalization | Validation rules | Default | Pass examples | Fail examples
Rules must be testable (no vague wording).
Then output:
1) A list of edge cases to test (CSV + JSON).
2) Proposed test names with expected result (pass/fail + error code).
Finally, list any contradictions you notice (required vs default, min/max vs examples).
Después del primer borrador, afínalo pidiendo un ejemplo positivo y uno negativo por regla. Eso empuja la cobertura de esquinas complicadas como cadenas vacías, valores solo con espacios, columnas faltantes, null vs "null", enteros muy grandes, notación científica, IDs duplicados y campos JSON extra.
Para un escenario concreto, imagina importar “customers” desde CSV: email es requerido, phone es opcional y signup_date por defecto es hoy si falta. El modelo debe señalar una contradicción si también dices “signup_date es requerido”. Debe proponer pruebas como import_customers_missing_email_returns_row_error y especificar el código de error y la forma del mensaje que devuelves.
Haz una pasada más antes de implementar: pide al modelo que replantee las reglas como una lista de verificación y que señale dónde defaults, campos requeridos y normalización podrían entrar en conflicto. Ese paso de revisión atrapa mucho comportamiento que genera tickets.
Las pruebas fuzz evitan que “archivos raros” se conviertan en tickets de soporte. Empieza desde un pequeño conjunto de archivos válidos y genera miles de variaciones ligeramente rotas, y asegúrate de que tu importador reaccione de forma segura y clara.
Comienza con un pequeño corpus semilla de ejemplos válidos que representen uso real: el archivo válido más pequeño, un archivo típico y un archivo grande. Para JSON, incluye un objeto, muchos objetos y estructuras anidadas si las soportas.
Luego añade un mutador automatizado que toque una cosa a la vez. Mantén las mutaciones reproducibles registrando la semilla aleatoria para poder reproducir fallos.
Dimensiones de fuzz que capturan la mayoría de problemas reales:
No te quedes en la sintaxis. Añade fuzz semántico también: intercambia campos similares (email vs username), fechas extremas, IDs duplicados, cantidades negativas o valores que violen enums.
Las pruebas fuzz solo ayudan si los criterios de pase son estrictos. Tu importador nunca debería colapsar o bloquearse, y los errores deben ser consistentes y accionables.
Un conjunto práctico de reglas de pase:
Ejecuta estas pruebas en CI en cada cambio. Cuando encuentres un fallo, guarda el archivo exacto como fixture y añade una prueba de regresión para que no vuelva.
Si usas Claude Code para este trabajo, haz que genere fixtures semilla que coincidan con tu contrato, un plan de mutaciones y los errores esperados. Tú eliges las reglas, pero obtendrás una superficie de prueba amplia rápido, especialmente para comillas en CSV y esquinas de JSON.
La mayoría de los tickets de importación vienen de reglas poco claras y feedback poco útil.
Una trampa común es el parsing “best effort” que no está documentado. Si tu importador recorta espacios en silencio, acepta comas y punto y coma, o adivina formatos de fecha, los usuarios construyen flujos alrededor de esas conjeturas. Luego un pequeño cambio, o un generador de archivos distinto, rompe todo. Elige el comportamiento, documéntalo y pruébalo.
Otro repetidor frecuente es el mensaje genérico. “Invalid CSV” o “Bad request” obliga a los usuarios a adivinar. Suben el mismo archivo cinco veces y soporte acaba pidiendo el archivo de todas formas. Los errores deben apuntar a una fila, un campo, una razón clara y un código estable.
Fallar todo el archivo por una fila mala también es frecuente. A veces eso es correcto (por ejemplo, importes financieros donde datos parciales son peligrosos). Muchas importaciones de negocio pueden continuar y reportar un resumen, siempre que ofrezcas una opción explícita como modo estricto vs importación parcial.
Los problemas de codificación de texto generan tickets persistentes. UTF-8 es el por defecto correcto, pero los CSV reales a menudo incluyen BOM, comillas rizadas o espacios no separables copiados de hojas de cálculo. Manéjalos de forma consistente y reporta lo detectado para que los usuarios puedan arreglar la configuración de exportación.
Por último, cambiar códigos de error entre versiones rompe clientes y automatizaciones. Mejora el wording si quieres, pero mantén códigos y significados estables. Versionéalos solo cuando sea estrictamente necesario.
Trampas a proteger desde el inicio:
Ejemplo: un cliente exporta un CSV desde Excel, que añade un BOM y formatea fechas como 03/04/2026. Tu importador adivina MM/DD, pero el cliente esperaba DD/MM. Si tu reporte de errores incluye el formato detectado, el campo exacto y una sugerencia de corrección, el usuario puede arreglarlo sin ida y vuelta.
La mayoría de los problemas de importación son pequeños desajustes entre lo que los usuarios creen que significa el archivo y lo que tu sistema acepta. Trátalo como una puerta de release.
Una prueba práctica: usa un archivo intencionalmente desordenado. Ejemplo: un CSV donde el encabezado aparece dos veces (dos columnas “email”), un campo boolean usa “Y” y una fecha es “03/04/05”. Tu importador no debería adivinar. Debe aplicar una regla documentada de mapeo o rechazar con un error específico.
Dos comprobaciones que los equipos suelen saltarse:
Primero, verifica que el importador reporta errores con suficiente detalle de ubicación para corregir el archivo de origen. “Invalid date” no es accionable. “Fila 42, columna start_date: se esperaba YYYY-MM-DD, se recibió 03/04/05” sí lo es.
Segundo, ejecuta el mismo archivo inválido dos veces y compara resultados. Si el orden de errores cambia, los códigos cambian o los números de fila fluctúan, los usuarios pierden confianza. El comportamiento determinista es aburrido, y esa es la idea.
Una importación común son pedidos de clientes que vienen de una exportación de hoja de cálculo. Alguien exporta un CSV de un sistema antiguo, lo edita en Excel y luego lo sube. La mayoría de los tickets ocurren cuando el importador “arregla” datos en silencio o cuando el mensaje de error no dice qué cambiar.
Imagina un archivo llamado orders.csv con columnas: order_id,customer_email,order_date,currency,total_amount.
Aquí hay tres filas malas realistas (como las vería el usuario):
order_id,customer_email,order_date,currency,total_amount
A-1001,[email protected],2026-01-05,USD,129.99
A-1002,not-an-email,01/06/2026,USD,49.00
,[email protected],2026-01-07,US, -10
La fila 2 tiene un email inválido y una fecha ambigua. La fila 3 carece de order_id, tiene un código de moneda no soportado (US en lugar de USD) y un importe negativo.
Si tu API devuelve errores, mantén la forma consistente y específica. Aquí hay un ejemplo de respuesta que soporta éxito parcial:
{
"correlation_id": "imp_20260109_7f3a9d",
"import_id": "ord_01HZZ...",
"status": "partial_success",
"summary": {
"total_rows": 3,
"imported_rows": 1,
"failed_rows": 2
},
"errors": [
{
"row_number": 2,
"field": "customer_email",
"code": "invalid_email",
"message": "Email must contain a valid domain.",
"value": "not-an-email"
},
{
"row_number": 2,
"field": "order_date",
"code": "invalid_date_format",
"message": "Use ISO-8601 (YYYY-MM-DD).",
"value": "01/06/2026"
},
{
"row_number": 3,
"field": "order_id",
"code": "required",
"message": "order_id is required.",
"value": ""
},
{
"row_number": 3,
"field": "currency",
"code": "unsupported_currency",
"message": "Allowed values: USD, EUR, GBP.",
"value": "US"
},
{
"row_number": 3,
"field": "total_amount",
"code": "must_be_positive",
"message": "total_amount must be greater than 0.",
"value": " -10"
}
],
"retry": {
"mode": "upload_failed_only",
"failed_row_numbers": [2, 3]
}
}
El éxito parcial importa porque los usuarios no deberían tener que volver a subir todo el archivo. Un flujo de reintento simple es: arreglar solo las filas fallidas, exportar un CSV pequeño con las filas 2 y 3 y volver a subir. Tu importador debería tratar esto como idempotente cuando order_id está presente, así que el “reintento” actualiza los mismos registros en lugar de crear duplicados.
Para soporte, correlation_id es la vía más rápida al diagnóstico. Un agente de soporte puede pedir ese único valor, encontrar la ejecución en logs y confirmar si el parser vio columnas extras, un delimitador equivocado o codificación inesperada.
Pasos siguientes que hacen esto repetible:
Most failures come from messy real-world data, not “bad code.” CSV issues are usually about shape (headers, delimiter, quoting, encoding), while JSON issues are usually about meaning (types, null vs empty, unexpected nesting). Treat both as untrusted input and validate against an explicit contract.
Define three outcomes up front:
Pick a default (many products choose partial) and make it consistent across UI and API.
Write down an import contract before writing validation:
This prevents “it worked yesterday” surprises when behavior changes.
Default to one unambiguous format per field (for example, dates as YYYY-MM-DD). If you accept variants, make it explicit and predictable (for example, accept true/false/1/0, but not every spreadsheet guess). Avoid guessing ambiguous dates like 01/02/03; either require ISO format or reject with a clear error.
Decide:
If users can retry imports, combine this with idempotency so the same upload doesn’t create duplicates.
Use layers instead of one giant validate():
Small named rules are easier to test and safer to change.
Return a stable error shape with:
Always return a consistent summary, even when there are errors:
Support retries explicitly:
idempotencyKey (or use a file hash)importId if the same request is repeatedWithout this, normal user retries can double-create records.
Start with a few known-good seed files, then generate many small mutations (one change at a time):
NaN/Infinity in JSON)A fuzz test “passes” when the importer never crashes/hangs and returns deterministic, actionable errors.
code (stable identifier)message (human-friendly)path/field (column name or JSON pointer)row/line (for CSV)severity (error vs warning)Make it actionable by including what was expected and what was received when possible.
created, updated, skipped, failed, plus totalRows/totalRecordsstatus (success, rejected, completed_with_errors)startedAt, finishedAt)correlationId for support/debuggingFor large files, include a small errorsSample and a way to fetch the full report later.