SAP B1 DI API Fehlercodes: -5002, -1029, -2035 erklärt
Von Zain Abbas, Kodenova · Aktualisiert am
Ein DI-API-Aufruf liefert bei Erfolg 0 und bei einem Fehler eine negative Zahl. Die Zahl verrät die Kategorie, der Text aus Company.GetLastError die Ursache. In den SAP-Business-One-Integrationen, die ich baue (Webportale, Add-ons, E-Invoicing-Schnittstellen), decken sieben Codes fast alle Fehler ab: -5002, -1029, -2035, -2028, -5006, -5001 und -4006. Im Folgenden erkläre ich, was jeder Code bedeutet, welche Meldung SAP in unseren Tests genau zurückgegeben hat und wie Sie den Fehler beheben.
Wie liest man einen DI-API-Fehler richtig aus?
Jedes Add(), Update(), Cancel() und Remove() gibt einen int zurück. Ist er ungleich 0, rufen Sie sofort GetLastError auf. Der Fehler hängt am Company-Objekt, und der nächste DI-Aufruf überschreibt ihn. Ein Logeintrag, der erst nach einem zweiten Aufruf geschrieben wird, zeigt daher oft den falschen Fehler oder gar keinen.
Zwei Fallen aus echten Projekten:
- Late Binding in .NET. Wenn Sie das Company-Objekt als
dynamicverwenden, wirftc.GetLastError(out int code, out string msg)die AusnahmeCould not convert argument 0 for call to GetLastError. Der Dynamic Binder von .NET kann COM-out-Parameter nicht übergeben. Rufen Sie die Methode stattdessen per Reflection auf. - Nur die Nummer protokollieren.
-5002allein hilft niemandem. Der Text enthält eine interne Meldungsnummer und oft das genaue Feld, etwa[INC1.UomCode]oder[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);
}
Im Service Layer kommen dieselben Codes als JSON zurück, zum Beispiel {"error":{"code":-4006,"message":{"lang":"en-us","value":"Update the exchange rate"}}}.
Welche DI-API-Fehlercodes treten am häufigsten auf?
| Code | SAP-Text (gekürzt) | Was er meist bedeutet | Was Sie zuerst prüfen sollten |
|---|---|---|---|
| -5002 | Unterschiedlich, z. B. “UoM code cannot be empty [INC1.UomCode]” | Eine Geschäftsvalidierung ist fehlgeschlagen; der Text nennt das Feld | Das Feld in eckigen Klammern |
| -1029 | “Field cannot be updated” | Sie haben ein Feld geändert, das SAP in diesem Beleg oder Datensatz sperrt | Belegstatus, gebuchte Zeilen, Kontobuchungen |
| -2035 | “This entry already exists in the following tables” | Doppelter Schlüssel: UDF, UDT, Geschäftspartner- oder Artikelnummer | Vor dem Add auf Existenz prüfen |
| -2028 | “No matching records found” | Schlüssel, Code oder gespeicherte Abfrage existiert in diesem Mandanten nicht | Firmendatenbank und exakter Schlüssel |
| -5006 | “The requested action is not supported for this object” | Falsche Methode für diesen Objekttyp, z. B. Cancel auf einer Rechnung | Die Methode verwenden, die das Objekt unterstützt |
| -5001 | “Internal error” | Fehlerhafte Eingabe, oft ein Nullwert im Service-Layer-Body | Nullwerte und leere Strings entfernen |
| -4006 | “Update the exchange rate” | Kein Kurs für die Belegwährung an diesem Datum | ORTT für das Buchungsdatum |
Was bedeutet -5002 in SAP Business One?
-5002 ist ein Sammelcode. SAP gibt ihn bei den meisten Validierungen von Belegen und Stammdaten zurück und schreibt den eigentlichen Grund in den Text. Die folgenden Meldungen haben wir auf echten Testmandanten erhalten, jeweils mit der Lösung:
[-5002] 1470000542 - UoM code cannot be empty [INC1.UomCode]bei einer Inventurzählung. Der Artikel hatte eine Mengeneinheitengruppe mit zwei Einheiten (MT/KG). Artikel mit nur einer Mengeneinheit liefen durch. Lösung:UoMCode(die Lagermengeneinheit des Artikels) zusammen mit der gezählten Menge übergeben.[-5002] 480000112 ... does not existbei einem Warenausgang mit Seriennummern. Wir hatten die interne Seriennummer übergeben. Ausgehende Belege benötigen dieSystemSerialNumber(den fortlaufenden Zähler, den SAP pro Artikel vergibt). Interne Seriennummer und Herstellerseriennummer verwenden Sie nur bei Eingängen.- “G/L Increase account is missing” bei einer Bestandsneubewertung. Im Mandanten waren weder für die Periode noch für ein Lager Sachkonten für Erhöhung und Verminderung (Increase/Decrease) hinterlegt. Das ist ein Customizing-Problem, kein Codeproblem: Hinterlegen Sie die Konten in der Sachkontenfindung.
- Basisbeleg bereits geschlossen. Wenn Sie eine Lieferung aus einem Kundenauftrag kopieren, der bereits vollständig geliefert oder geschlossen ist, schlägt das mit -5002 fehl. Prüfen Sie die Basiszeile, bevor Sie den Zielbeleg aufbauen (Abfrage siehe unten).
- Ein UDF vom Typ Float ohne SubType. Das Anlegen eines numerischen UDF mit
st_Noneoder ohneEditSizelieferte -5002. Setzen Sie SubType auf Price, Quantity, Rate, Sum oder Percentage und geben Sie die Feldgröße an. - Eine Umlagerung auf Basis einer Umlagerungsanforderung. Einige DI-Builds lehnten eine
OWTR-Zeile mit Bezug auf eineOWTQ-Basis (BaseType 1250000001) ab, die der Service Layer mit denselben Daten akzeptierte. Wir versuchen es inzwischen einmal erneut als einfache Kopie und weisen den Anwender darauf hin, die Anforderung manuell zu schließen. - Anlagen an einem geschlossenen Objekt. SAP akzeptierte Anlagenverknüpfungen nur bei Rahmenverträgen im Entwurfsstatus und bei offenen Serviceabrufen. Genehmigte Rahmenverträge und geschlossene Serviceabrufe quittierten das mit -5002.
Ein weiterer Fall hat mich einen ganzen Nachmittag gekostet: Als wir über den Service Layer ein bereits vorhandenes UDF anlegen wollten, lieferte SAP nicht -2035, sondern [-5002] No records. Verlassen Sie sich also nicht allein auf -2035, um “existiert bereits” zu erkennen, sondern prüfen Sie vorher CUFD.
Warum erhalte ich -1029 “Field cannot be updated”?
-1029 bedeutet, dass das Feld zwar existiert, SAP aber keine Änderung im aktuellen Zustand des Objekts zulässt. Das Feld in eckigen Klammern verrät, um welches es geht. Fälle aus unseren Tests:
[-1029] [DocumentLines.UnitPrice][line: 1] 'Field cannot be updated'bei einer Retoure und bei einer Ausgangsgutschrift. SAP sperrt Preis und Rabatt dieser Zeilen, sobald sie gebucht sind. Die Bemerkungen im Belegkopf lassen sich weiterhin ändern.[ORDR.VatSum]beim Bearbeiten eines geschlossenen Verkaufsbelegs. Geschlossene und stornierte Belege erlauben Änderungen an Bemerkungen, jede Änderung an Zeilen, Preisen oder Steuern führt jedoch zu -1029. Prüfen SieDocStatus, bevor Sie überhaupt einen Bearbeiten-Button anbieten.[OACT.Postable]beim “Deaktivieren” eines Sachkontos, auf dem bereits gebucht wurde. Das Portal hat die falsche Eigenschaft gepatcht. Um ein Konto inaktiv zu setzen, setzen SieFrozenFor = Y(bei Bedarf mitFrozenFrom/FrozenTofür einen Zeitraum) und lassenPostableunverändert.- Eine kopierte Bestellzeile. Sobald für eine Bestellzeile teilweise Ware eingegangen ist (offene Menge kleiner als Menge), sperrt SAP Preis, Rabatt und Menge. Sperren Sie diese Eingabefelder auch in Ihrer Oberfläche, damit der Anwender gar nicht erst auf den Fehler stößt.
Ein älterer Thread in der SAP Community zeigt denselben Code für ORDR.DocRate, das Verhalten ist also nicht neu. Verstehen Sie -1029 als “Ihre Oberfläche hat den Anwender etwas bearbeiten lassen, das SAP als endgültig betrachtet”.
Wie behebt man -2035 “This entry already exists”?
-2035 steht für einen doppelten Schlüssel. Der Fehler tritt vor allem auf, wenn ein Add-on oder eine Integration beim Start seine UDTs und UDFs anlegt oder wenn ein Import dieselbe Geschäftspartner- oder Artikelnummer zweimal sendet.
Machen Sie die Schemaanlage idempotent: Feld zuerst nachschlagen, nur anlegen, wenn es fehlt, und -2035 beim Anlegen als Erfolg werten. Bei Bewegungs- und Stammdaten prüfen Sie vor Add() anhand Ihres externen Schlüssels. Bei Ausgangs- oder Eingangsrechnungen aus einem Import ist das CardCode plus 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;
Beachten Sie, dass AliasID in CUFD ohne das Präfix U_ gespeichert wird.
Was bedeutet -2028 “No matching records found”?
Der angeforderte Datensatz existiert in dieser Firmendatenbank nicht. In der DI API liefert GetByKey statt -2028 einfach false, prüfen Sie den Rückgabewert also immer. Im Service Layer erhalten Sie -2028 bei einem GET über den Schlüssel und auch bei SQLQueries('code')/List, wenn die gespeicherte Abfrage in diesem Mandanten nicht existiert. Diesen Fall und wie Sie die Abfrage automatisch neu anlegen, behandelt der Leitfaden zu Service-Layer-SQLQueries-Fehlern.
Häufige Ursachen: Sie sind an einem anderen Mandanten angemeldet (Test statt Produktion), der Code unterscheidet sich in Groß-/Kleinschreibung oder hat nachgestellte Leerzeichen, oder Sie übergeben eine DocNum, wo SAP einen DocEntry erwartet.
Warum liefert Cancel() bei einer Ausgangsrechnung -5006?
-5006 besagt, dass die Methode für dieses Objekt nicht unterstützt wird. Der klassische Fall: Documents.Cancel() auf einer Ausgangsrechnung oder einer Lieferung. Buchungsrelevante Belege storniert SAP über einen Stornobeleg. Laden Sie die Rechnung und rufen Sie CreateCancellationDocument() auf. Die Methode gibt einen neuen Beleg im Speicher zurück (keinen int), auf dem Sie anschließend Add() aufrufen. Der Originalbeleg wird danach als storniert markiert.
Kundenaufträge, Bestellungen, Bestellanforderungen und Angebote unterstützen das einfache Cancel(). Bei Bestandsbuchungen ist es umgekehrt: In der DI-Version, die wir einsetzen, bieten Wareneingänge (59), Warenausgänge (60) und Bestandsumlagerungen (67) CreateCancellationDocument gar nicht an, und Cancel() funktioniert. Ordnen Sie die Stornomethode pro Objekttyp zu, statt für alles denselben Stornoweg zu verwenden.
Was verursacht -5001 “Internal error”?
Ein nacktes -5001 Internal error nennt keinerlei Details und ist damit am schwersten nachzuverfolgen. In unserer Arbeit mit dem Service Layer war die Ursache ein JSON-Body mit "Field": null. In .NET überspringt JsonIgnoreCondition.WhenWritingNull zwar Null-Eigenschaften von Objekten, aber nicht Nullwerte in einem Dictionary. Ein Payload, der aus einem Dictionary<string, object> aufgebaut wird, sendet sie also trotzdem mit. Lösung: Fügen Sie Felder über eine Hilfsmethode hinzu, die Nullwerte und leere Strings verwirft. Dann sehen Sie -5001 aus dieser Quelle nicht wieder.
Wie behebt man -4006 “Update the exchange rate”?
Der Beleg ist in Fremdwährung, und in ORTT gibt es für diese Währung keinen Kurs zum Buchungsdatum. SAP rät keinen Kurs. Pflegen Sie entweder vorher den Tageskurs ein, oder setzen Sie DocRate im Beleg, wenn Ihr Quellsystem den vereinbarten Kurs bereits kennt.
-- 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';
Wie sollte eine Integration mit diesen Fehlern umgehen?
Was sich bei uns im Produktivbetrieb bewährt hat:
- Code, vollständigen Text, Objekttyp und Ihre eigene Referenz protokollieren (zum Beispiel die Auftragsnummer im Portal), und zwar bei jedem Fehler.
- Fehler in “wiederholen” und “abbrechen” einteilen. Ein Timeout oder eine verlorene Sitzung kann wiederholt werden. -5002, -1029, -2035 und -5006 sind Daten- oder Designprobleme; ein erneuter Versuch erzeugt nur Rauschen. Bei einer fehlenden gespeicherten Abfrage (-2028 bei SQLQueries) ist es dagegen unbedenklich, sie neu anzulegen und einmal erneut zu versuchen.
- Für den Anwender übersetzen, den Originaltext für den Support behalten. “Für diese Zeile ist bereits Ware eingegangen, daher ist der Preis gesperrt” hilft einem Einkäufer mehr als
[-1029] [DocumentLines.UnitPrice]. Hängen Sie den SAP-Text in einem Detailbereich an. - Vorbeugen statt abfangen. Die meisten der oben genannten -1029- und -5002-Fälle verschwanden, als die Oberfläche Belegstatus, Zeilenstatus oder Artikeleinstellungen vor dem Senden prüfte.
Wenn Sie für ein neues Projekt zwischen den beiden APIs wählen, vergleichen der Leitfaden zur Add-on-Entwicklung und der Service-Layer-Leitfaden beide Ansätze. Die Tabellenreferenz listet die Tabellen aus den Abfragen oben auf, und mit dem Service-Layer-Request-Builder können Sie einen Payload testen, bevor er Ihren Code erreicht. Wenn Sie eine Integration oder ein Add-on entwickeln und betreuen lassen möchten, finden Sie alles Weitere unter SAP-Business-One-Entwicklung.
Die oben zitierten Fehlermeldungen stammen aus Testläufen von Kodenova auf Testmandanten von SAP Business One 10.0 (DI API und Service Layer), Oktober 2026.
Quellen
- SAP Business One SDK-Hilfe 10.0: Beispiel zu Company.GetLastError
- SAP Community: ORDR.DocRate field cannot be updated (ODBC -1029)
- SAP Community: Service Layer -4006 "Update the exchange rate" bei einem Zahlungseingang
Passende Leistungen
Häufige Fragen
Wo finde ich die vollständige Liste der SAP Business One DI API Fehlercodes?
SAP veröffentlicht keine vollständige, aktuelle Liste. Die SDK-Hilfe erklärt GetLastError, und der eigentlich nützliche Teil ist der Meldungstext, der mit dem Code zurückkommt. Gerade -5002 deckt Hunderte unterschiedlicher Validierungen ab. Protokollieren Sie deshalb immer den vollständigen Text, nicht nur die Nummer.
Liefern Service Layer und DI API dieselben Fehlercodes?
Größtenteils ja. Der Service Layer nutzt dieselbe Geschäftslogik, daher bedeuten -5002, -1029, -2035 und -2028 in beiden dasselbe. Der Service Layer verpackt sie lediglich in JSON: error.code und error.message.value.
Wie storniere ich eine Ausgangsrechnung über die DI API?
Nicht mit Cancel(), das liefert -5006. Rufen Sie auf der geladenen Rechnung CreateCancellationDocument() auf und führen Sie anschließend Add() auf dem zurückgegebenen Beleg aus. Kundenaufträge, Bestellungen und Angebote unterstützen Cancel() dagegen.
Bereit für den Start?
Sagen Sie uns, was Sie brauchen. Sie erhalten eine klare technische Antwort, einen festen Leistungsumfang und einen Preis, in der Regel innerhalb von 24 Stunden.
