Códigos de error de la DI API de SAP B1: qué significan -5002, -1029, -2035 y -5006 y cómo resolverlos
Por Zain Abbas, Kodenova · Actualizado el
Una llamada a la DI API devuelve 0 si tiene éxito y un número negativo si falla. Ese número indica la categoría; el texto de Company.GetLastError indica la causa. En las integraciones de SAP Business One que construyo (portales web, add-ons, puentes de facturación electrónica), siete códigos cubren casi todos los fallos: -5002, -1029, -2035, -2028, -5006, -5001 y -4006. A continuación explico qué significa cada uno, el mensaje exacto que SAP devolvió en nuestras pruebas y la solución.
¿Cómo se lee correctamente un error de la DI API?
Cada Add(), Update(), Cancel() y Remove() devuelve un int. Si no es 0, llame a GetLastError de inmediato. El error pertenece al objeto Company, y la siguiente llamada a la DI lo sobrescribe, así que una línea de log escrita después de una segunda llamada suele mostrar el error equivocado o ninguno.
Dos trampas de proyectos reales:
- Código .NET con enlace tardío (late binding). Si usa
dynamicpara el objeto Company,c.GetLastError(out int code, out string msg)lanzaCould not convert argument 0 for call to GetLastError. El enlazador dinámico de .NET no puede pasar argumentos COMout. Llámelo mediante reflexión. - Registrar solo el número.
-5002por sí solo no sirve. El texto incluye un número de mensaje interno y a menudo el campo exacto, como[INC1.UomCode]o[DocumentLines.UnitPrice][line: 1].
// Read the DI error without dynamic: works with late binding (no Interop DLL)
public static (int Code, string Message) ReadLastError(object company)
{
var args = new object[] { 0, null };
var byRef = new ParameterModifier(2);
byRef[0] = true; byRef[1] = true;
company.GetType().InvokeMember("GetLastError",
BindingFlags.InvokeMethod, null, company, args,
new[] { byRef }, CultureInfo.InvariantCulture, null);
return (Convert.ToInt32(args[0]), Convert.ToString(args[1]) ?? "");
}
int rc = doc.Add();
if (rc != 0)
{
var (code, msg) = ReadLastError(company); // read it NOW, before any other DI call
log.Error("DI Add failed [{Code}] {Msg}", code, msg);
}
En el Service Layer, los mismos códigos llegan como JSON, por ejemplo {"error":{"code":-4006,"message":{"lang":"en-us","value":"Update the exchange rate"}}}.
¿Qué códigos de error de la DI API aparecen con más frecuencia?
| Código | Texto de SAP (resumido) | Qué suele significar | Qué revisar primero |
|---|---|---|---|
| -5002 | Variable, p. ej. “UoM code cannot be empty [INC1.UomCode]” | Falló una validación de negocio; el texto indica el campo | Lea el campo entre corchetes |
| -1029 | “Field cannot be updated” (el campo no se puede actualizar) | Cambió un campo que SAP bloquea en ese documento o registro | Estado del documento, líneas contabilizadas, contabilizaciones en la cuenta |
| -2035 | “This entry already exists in the following tables” (esta entrada ya existe) | Clave duplicada: UDF, UDT, código de socio de negocios, código de artículo | Verifique si existe antes de Add |
| -2028 | “No matching records found” (no se encontraron registros coincidentes) | La clave, el código o la consulta guardada no existe en esta empresa | Base de datos de la empresa y clave exacta |
| -5006 | “The requested action is not supported for this object” (acción no soportada para este objeto) | Método incorrecto para ese tipo de objeto, p. ej. Cancel en una factura | Use el método que ese objeto admite |
| -5001 | “Internal error” (error interno) | Entrada mal formada, a menudo un valor null en el cuerpo enviado al Service Layer | Elimine nulls y cadenas vacías |
| -4006 | “Update the exchange rate” (actualice el tipo de cambio) | No hay tipo de cambio para la moneda del documento en esa fecha | ORTT para la fecha de contabilización |
¿Qué significa -5002 en SAP Business One?
-5002 es un contenedor. SAP lo devuelve en la mayoría de las validaciones de documentos y datos maestros, y pone la razón real en el texto. Estos son mensajes que obtuvimos en empresas de prueba en vivo, con la solución de cada uno:
[-5002] 1470000542 - UoM code cannot be empty [INC1.UomCode]en un recuento de inventario. El artículo tenía un grupo de unidades de medida con dos unidades (MT/KG). Los artículos con una sola unidad pasaban. Solución: envíeUoMCode(la unidad de medida de inventario del artículo) junto con la cantidad contada.[-5002] 480000112 ... does not exist(no existe) en una salida de mercancías con números de serie. Enviamos el número de serie interno. Los documentos de salida necesitan elSystemSerialNumber(el numerador que SAP asigna por artículo). Deje el número de serie interno y el del fabricante solo para las entradas.- “G/L Increase account is missing” (falta la cuenta de mayor de aumento) en una revalorización de inventario. La empresa no tenía cuentas de mayor de aumento/disminución definidas para el período ni para ningún almacén. Es un problema de configuración, no de código: defina las cuentas en la determinación de cuentas de mayor.
- Documento base ya cerrado. Copiar una entrega desde un pedido de cliente totalmente entregado o cerrado falla con -5002. Revise la línea base antes de construir el documento destino (consulta más abajo).
- Un UDF de tipo Float sin SubType. Crear un UDF numérico con
st_Noneo sinEditSizedevolvió -5002. Defina SubType como Price, Quantity, Rate, Sum o Percentage, y defina el tamaño. - Una transferencia basada en una solicitud de traslado. Algunas versiones de la DI rechazaron una línea de
OWTRvinculada a una baseOWTQ(BaseType 1250000001) que el Service Layer aceptaba con los mismos datos. Ahora reintentamos una vez como copia simple y le indicamos al usuario que cierre la solicitud a mano. - Anexos en un objeto cerrado. SAP aceptó vínculos de anexos solo en acuerdos globales en borrador y en llamadas de servicio abiertas. Los acuerdos aprobados y las llamadas cerradas respondieron -5002.
Uno más que nos hizo perder una tarde: cuando intentamos crear mediante el Service Layer un UDF que ya existía, SAP no devolvió -2035. Devolvió [-5002] No records. Así que no dependa solo de -2035 para detectar “ya existe”; consulte primero CUFD.
¿Por qué aparece -1029 “Field cannot be updated”?
-1029 significa que el campo existe pero SAP no le permite cambiarlo en el estado actual del objeto. El campo entre corchetes le dice cuál es. Casos de nuestras pruebas:
[-1029] [DocumentLines.UnitPrice][line: 1] 'Field cannot be updated'en una devolución de ventas y en una nota de crédito de clientes. SAP bloquea el precio y el descuento de esas líneas una vez contabilizadas. Los comentarios de la cabecera sí se actualizan.[ORDR.VatSum]al editar un documento de ventas cerrado. Los documentos cerrados y cancelados aceptan cambios en los comentarios, pero cualquier cambio de línea, precio o impuesto da -1029. ReviseDocStatusantes de mostrar un botón de edición.[OACT.Postable]al “desactivar” una cuenta de mayor que ya tiene contabilizaciones. El portal estaba modificando la propiedad equivocada. Para inactivar una cuenta, definaFrozenFor = Y(conFrozenFrom/FrozenTosi necesita un rango de fechas) y no toquePostable.- Una línea copiada de un pedido de compra. Cuando una línea de pedido de compra se ha recibido parcialmente (cantidad abierta menor que la cantidad), SAP bloquea su precio, descuento y cantidad. Bloquee esas entradas en su interfaz para que el usuario nunca llegue al error.
Un hilo antiguo de SAP Community muestra el mismo código en ORDR.DocRate, así que no es un comportamiento nuevo. Trate -1029 como “su interfaz dejó al usuario editar algo que SAP considera definitivo”.
¿Cómo se resuelve -2035 “This entry already exists”?
-2035 es una clave duplicada. Aparece sobre todo cuando un add-on o una integración crea sus UDT y UDF al iniciar, o cuando una importación envía dos veces el mismo código de socio de negocios o de artículo.
Haga que la creación del esquema sea idempotente: busque primero el campo, créelo solo si falta y trate un -2035 en la creación como éxito. Para datos de negocio, verifique por su clave externa antes de Add(). Para facturas de clientes o de proveedores provenientes de una importación, esa clave es CardCode más NumAtCard.
-- SQL Server: does the UDF exist? (TableID without @ for system tables)
SELECT FieldID, AliasID, Descr
FROM CUFD
WHERE TableID = 'OITM' AND AliasID = 'HSCode';
-- SAP HANA
SELECT "FieldID", "AliasID", "Descr"
FROM "CUFD"
WHERE "TableID" = 'OITM' AND "AliasID" = 'HSCode';
-- Is the base sales order line still open before you copy it? (SQL Server)
SELECT T0.DocNum, T0.DocStatus, T1.LineNum, T1.LineStatus, T1.OpenQty
FROM ORDR T0 JOIN RDR1 T1 ON T1.DocEntry = T0.DocEntry
WHERE T0.DocEntry = 1234;
-- SAP HANA
SELECT T0."DocNum", T0."DocStatus", T1."LineNum", T1."LineStatus", T1."OpenQty"
FROM "ORDR" T0 JOIN "RDR1" T1 ON T1."DocEntry" = T0."DocEntry"
WHERE T0."DocEntry" = 1234;
Tenga en cuenta que AliasID en CUFD se guarda sin el prefijo U_.
¿Qué significa -2028 “No matching records found”?
El registro que solicitó no está en esta base de datos de la empresa. En la DI API, GetByKey devuelve false en lugar de lanzar -2028, así que compruebe siempre su resultado. En el Service Layer obtiene -2028 en un GET por clave, y también en SQLQueries('code')/List cuando la consulta guardada no existe en esa empresa. Ese caso, y cómo recrear la consulta automáticamente, se explica en la guía de errores de SQLQueries del Service Layer.
Causas comunes: tiene sesión iniciada en otra empresa (pruebas frente a producción), el código tiene otras mayúsculas/minúsculas o espacios al final, o la clave es un DocNum donde SAP espera un DocEntry.
¿Por qué Cancel() devuelve -5006 en una factura de clientes?
-5006 indica que el método no está soportado para ese objeto. El caso clásico: Documents.Cancel() en una factura de clientes o una entrega. SAP cancela los documentos contables creando un documento de reversión. Cargue la factura, llame a CreateCancellationDocument(), que devuelve un nuevo documento en memoria (no un int), y luego llame a Add() sobre él. El original queda marcado como cancelado.
Los pedidos de cliente, los pedidos de compra, las solicitudes de compra y las ofertas sí admiten Cancel() simple. Las contabilizaciones de inventario funcionan al revés: en la versión de la DI que usamos, las entradas de mercancías (59), las salidas de mercancías (60) y las transferencias de stock (67) no exponen CreateCancellationDocument en absoluto, y Cancel() funciona. Defina el método por tipo de objeto en lugar de usar una sola ruta de cancelación para todo.
¿Qué causa -5001 “Internal error”?
Un -5001 Internal error a secas no nombra nada, lo que lo convierte en el más difícil de rastrear. En nuestro trabajo con el Service Layer, la causa era un cuerpo JSON con "Field": null. En .NET, JsonIgnoreCondition.WhenWritingNull omite las propiedades null de un objeto pero no los valores null de un diccionario, así que un payload construido desde un Dictionary<string, object> los sigue enviando. Solución: agregue los campos mediante un helper que descarte nulls y cadenas vacías, y no volverá a ver -5001 por esa causa.
¿Cómo se resuelve -4006 “Update the exchange rate”?
El documento está en moneda extranjera y no hay tipo de cambio en ORTT para esa moneda en la fecha de contabilización. SAP no adivina un tipo de cambio. Cargue primero el tipo de cambio del día, o defina DocRate en el documento cuando su sistema de origen ya tenga el tipo acordado.
-- SQL Server: is there a rate for USD on the posting date?
SELECT RateDate, Currency, Rate FROM ORTT
WHERE Currency = 'USD' AND RateDate = '2026-10-25';
-- SAP HANA
SELECT "RateDate", "Currency", "Rate" FROM "ORTT"
WHERE "Currency" = 'USD' AND "RateDate" = '2026-10-25';
¿Qué significan los errores de conexión -111, -132 y -8037 de la DI API?
Estos tres provienen de Company.Connect(), antes de tocar cualquier documento. -111 significa que la DI API no pudo abrir la base de datos SBO-COMMON, -132 significa que se rechazó el propio inicio de sesión de SAP Business One y -8037 significa que la DI API no pudo llegar al System Landscape Directory (SLD) con el nombre de servidor que usted le dio.
| Código | Texto de SAP | Causa habitual | Qué revisar primero |
|---|---|---|---|
| -111 | “Failed to connect to SBO-Common” (no se pudo conectar a SBO-Common) | La DI API no puede iniciar sesión en SBO-COMMON: Server o DbServerType incorrectos, credenciales de base de datos incorrectas o un parche de la DI API que no coincide con el servidor | Nombre del servidor y DbServerType; instale la DI API del mismo parche que el servidor |
| -132 | “Error during SBO user authentication” (error en la autenticación del usuario SBO) | LicenseServer sin configurar, un parche de la DI API que no coincide con la empresa o configuraciones de inicio de sesión mezcladas | Configure LicenseServer; con UseTrusted = true deje DbUserName y DbPassword vacíos; Server y SLDServer deben coincidir, incluidas mayúsculas y minúsculas |
| -8037 | “Failed to connect or logon to SLD” (no se pudo conectar o iniciar sesión en el SLD) | Company.Server no es el nombre registrado en el SLD / Control Center (por ejemplo localhost), o b1-local-machine.xml en la carpeta Conf de la DI API apunta a otro servidor | Use el nombre de servidor registrado exacto; copie b1-local-machine.xml de la carpeta Conf del cliente de SAP Business One a la carpeta Conf de la DI API |
Dos notas sobre -132. SAP lo relaciona con que la conexión de la DI API a la empresa no se autentica contra el servidor de licencias (SAP KBA 3394748). Y puede aparecer solo de vez en cuando: el SAP KBA 3663692 describe un -132 intermitente cuando muchos inicios de sesión de la DI API o del Service Layer se ejecutan al mismo tiempo, así que un portal web que abre una conexión nueva por solicitud debería reutilizar una sola conexión.
¿Cómo debe manejar estos errores una integración?
Lo que nos funciona en producción:
- Registre el código, el texto completo, el tipo de objeto y su propia referencia (por ejemplo, el número de pedido del portal) en cada fallo.
- Separe los errores entre reintentar y detenerse. Un timeout o una sesión perdida se pueden reintentar. -5002, -1029, -2035 y -5006 son problemas de datos o de diseño; reintentarlos solo genera ruido. Para una consulta guardada inexistente (-2028 en SQLQueries), recrearla y reintentar una vez es seguro.
- Traduzca para el usuario y conserve el texto original para soporte. “Esta línea ya fue recibida, por eso su precio está bloqueado” le sirve más a un comprador que
[-1029] [DocumentLines.UnitPrice]. Agregue el texto de SAP en una sección de detalles. - Prevenga en lugar de capturar. La mayoría de los casos de -1029 y -5002 anteriores desaparecieron cuando la interfaz verificó el estado del documento, el estado de la línea o la configuración del artículo antes de enviar.
Si está eligiendo entre las dos API para un proyecto nuevo, la guía de desarrollo de add-ons y la guía del Service Layer las comparan. La referencia de tablas lista las tablas usadas en las consultas anteriores, y el generador de solicitudes del Service Layer le ayuda a probar un payload antes de que llegue a su código. Si necesita construir y mantener una integración o un add-on, vea desarrollo para SAP Business One.
Los mensajes de error citados provienen de pruebas de Kodenova en empresas de prueba de SAP Business One 10.0 (DI API y Service Layer), octubre de 2026.
Fuentes
- SAP Business One SDK Help 10.0: ejemplo de Company.GetLastError
- SAP Community: ORDR.DocRate field cannot be updated (ODBC -1029)
- SAP Community: Service Layer -4006 "Update the exchange rate" en un pago recibido
- SAP KBA 3394748: la conexión de la DI API a la empresa falla con -132
- SAP KBA 3663692: -132 intermitente con muchos inicios de sesión simultáneos de DI API o Service Layer
- SAP Community: -132 Error during SBO user authentication (Server y SLDServer, UseTrusted)
- SAP KBA 3482586: la conexión de la DI API falla con -111
- Codeless Platforms: Failed to connect or logon to SLD, error code -8037
Servicios relacionados
Preguntas frecuentes
¿Dónde está la lista completa de códigos de error de la DI API de SAP Business One?
SAP no publica una lista completa y actualizada. La ayuda del SDK explica GetLastError, y la parte útil es el texto del mensaje que acompaña al código. Un -5002 en particular cubre cientos de validaciones distintas, así que registre el texto completo, no solo el número.
¿El Service Layer y la DI API devuelven los mismos códigos de error?
En su mayoría, sí. El Service Layer funciona sobre la misma lógica de negocio, por lo que -5002, -1029, -2035 y -2028 significan lo mismo en ambos. El Service Layer los envuelve en JSON: error.code y error.message.value.
¿Cómo cancelo una factura de clientes con la DI API?
No con Cancel(), que devuelve -5006. Llame a CreateCancellationDocument() sobre la factura cargada y luego ejecute Add() sobre el documento que devuelve. Los pedidos de cliente, los pedidos de compra y las ofertas sí admiten Cancel().
¿Por qué Company.Connect() devuelve -132?
-132 "Error during SBO user authentication" (error en la autenticación del usuario SBO) significa que la DI API llegó al servidor pero falló el inicio de sesión de SAP Business One. Verifique que LicenseServer esté configurado, que el parche de la DI API coincida con la versión de la base de datos de la empresa, que use un solo modo de inicio de sesión (con UseTrusted = true, deje DbUserName y DbPassword vacíos) y que Server y SLDServer usen el mismo nombre con las mismas mayúsculas y minúsculas. SAP también documenta que -132 aparece de forma intermitente cuando muchos inicios de sesión de la DI API o del Service Layer se ejecutan al mismo tiempo.
¿Listo para empezar?
Cuéntenos lo que necesita. Recibirá una respuesta técnica clara, un alcance definido y un precio fijo, normalmente en 24 horas.
