Zum Hauptinhalt springen

Fehlerbehandlung

Dieses Kapitel beschreibt, wie Fehler in GraphQL-Antworten zurückgegeben werden und wie sie behandelt werden.

Struktur der Fehlerantwort​

GraphQL-Fehler werden im Array errors der Antwort zurückgegeben. Jeder Fehler enthält:

{
"errors": [
{
"message": "Entity not found",
"locations": [
{
"line": 3,
"column": 5
}
],
"path": ["runtime", "industryEnergyEnergyMeter", "items"],
"extensions": {
"code": "ENTITY_NOT_FOUND",
"details": "No entity found with rtId: 65dc6d24cc529cdc46c84fcc"
}
}
],
"data": null
}

Fehlerfelder​

FeldBeschreibung
messageFür Menschen lesbare Fehlerbeschreibung
locationsPosition in der GraphQL-Query, an der der Fehler aufgetreten ist
pathPfad zu dem Feld, das den Fehler verursacht hat
extensions.codeMaschinenlesbarer Fehlercode
extensions.detailsZusätzliche Fehlerdetails

Partielle Antworten​

GraphQL kann partielle Daten zusammen mit Fehlern zurückgeben. Wenn einige Teile einer Query erfolgreich sind, während andere fehlschlagen, können Sie sowohl data als auch errors erhalten:

{
"errors": [
{
"message": "Access denied to field 'configuration'",
"path": ["runtime", "systemCommunicationAdapter", "items", 0, "configuration"]
}
],
"data": {
"runtime": {
"systemCommunicationAdapter": {
"items": [
{
"rtId": "65d5c447b420da3fb12381bc",
"name": "My Adapter",
"configuration": null
}
]
}
}
}
}

Häufige Fehlercodes​

Query-Fehler​

CodeBeschreibung
ENTITY_NOT_FOUNDDie angeforderte Entität existiert nicht
TYPE_NOT_FOUNDDie angegebene ckTypeId ist ungültig
INVALID_FILTERFilterparameter sind ungültig
INVALID_SORTSortierparameter sind ungültig
INVALID_CURSORDer Paginierungs-Cursor ist ungültig oder abgelaufen

Mutations-Fehler​

CodeBeschreibung
VALIDATION_ERRORDie Eingabedaten haben die Validierung nicht bestanden
REQUIRED_FIELD_MISSINGEin erforderliches Feld wurde nicht angegeben
INVALID_FIELD_VALUEDer Feldwert entspricht nicht dem erwarteten Typ oder Format
ENTITY_ALREADY_EXISTSEine Entität mit dem angegebenen Identifier existiert bereits
REFERENCE_NOT_FOUNDDie referenzierte Entität (z. B. in einer Assoziation) wurde nicht gefunden
CONSTRAINT_VIOLATIONDie Operation verletzt eine Bedingung (z. B. Multiplizität)

Autorisierungsfehler​

CodeBeschreibung
UNAUTHORIZEDAuthentifizierung erforderlich
FORBIDDENUnzureichende Berechtigungen für die Operation
ACCESS_DENIEDZugriff auf eine bestimmte Ressource verweigert
BLUEPRINT_LOCKEDDie Entität ist durch einen Blueprint gesperrt und kann von Benutzern nicht geändert oder gelöscht werden, siehe Durch Blueprint gesperrte Entitäten

Durch Blueprint gesperrte Entitäten​

Ein Blueprint kann produktseitige Entitäten ausliefern, zum Beispiel die Kategorisierungsregeln, auf die sich ein Buchhaltungs-Blueprint stützt. Für einen CK-Typ, der durch eine Datenrichtlinie mit ProtectBlueprintLocked geschützt ist (siehe Schreibgeschützt für Benutzer), kann ein Benutzer eine solche Entität nicht mehr ändern oder löschen. Der Schreibzugriff wird mit dem stabilen Fehlercode BLUEPRINT_LOCKED und der Engine-Meldungsnummer 6384 abgewiesen. Die Entität bleibt unverändert; Lesezugriffe sind nie betroffen.

GraphQL​

Der Fehler wird für die Mutationen create, update und delete zurückgegeben. Die extensions enthalten alles, was ein Client braucht, um „vom Produkt gesperrt“ statt eines allgemeinen Fehlers anzuzeigen:

{
"errors": [
{
"message": "Access denied: entity 'Accounting-1.0.0/CategorizationRule-1@65dc6d24cc529cdc46c84fcc' is locked by blueprint and cannot be changed.",
"path": ["runtime", "runtimeEntities", "update"],
"extensions": {
"code": "BLUEPRINT_LOCKED",
"messageNumber": 6384,
"ckTypeId": "Accounting-1.0.0/CategorizationRule-1",
"rtId": "65dc6d24cc529cdc46c84fcc",
"reason": "EntityLocked",
"items": [
{
"ckTypeId": "Accounting-1.0.0/CategorizationRule-1",
"rtId": "65dc6d24cc529cdc46c84fcc",
"reason": "EntityLocked"
}
]
}
}
],
"data": null
}
ExtensionBeschreibung
codeImmer BLUEPRINT_LOCKED. Prüfen Sie diesen Wert, nicht die Meldung.
messageNumberDie Meldungsnummer der Engine, 6384.
ckTypeId, rtIdDie erste abgewiesene Entität. rtId ist die von der Engine vergebene ID eines abgewiesenen Inserts.
reasonEntityLocked: Die gespeicherte Entität hat rtBlueprintLocked = true und kann nicht aktualisiert, ersetzt oder gelöscht werden. ProtectedAttributes: Die Änderung setzt oder ändert rtBlueprintLocked, rtBlueprintSource oder rtBlueprintAppliedAt, die auf geschützten Typen nur Blueprints verwalten dürfen.
itemsJe ein Eintrag (ckTypeId, rtId, reason) für jede abgewiesene Entität der Anfrage.

Eine Mutation wird als Ganzes angewendet: Ist eine Entität eines Batches gesperrt, wird nichts des Batches geschrieben, auch nicht die Entitäten, die nicht gesperrt sind. Entfernen Sie die gesperrten Entitäten aus der Anfrage und senden Sie sie erneut.

REST​

Eine REST-Aktion, die die Abweisung weitergibt, antwortet mit dem HTTP-Status 403 Forbidden und application/problem+json (RFC 9457), das denselben stabilen code trägt:

{
"type": "https://schemas.meshmakers.cloud/errors/blueprint-locked",
"title": "Entity is locked by a blueprint",
"status": 403,
"detail": "Access denied: entity 'Accounting-1.0.0/CategorizationRule-1@65dc6d24cc529cdc46c84fcc' is locked by blueprint and cannot be changed.",
"code": "BLUEPRINT_LOCKED",
"messageNumber": 6384,
"ckTypeId": "Accounting-1.0.0/CategorizationRule-1",
"rtId": "65dc6d24cc529cdc46c84fcc",
"reason": "EntityLocked",
"items": [
{ "ckTypeId": "Accounting-1.0.0/CategorizationRule-1", "rtId": "65dc6d24cc529cdc46c84fcc", "reason": "EntityLocked" }
]
}

Runtime-Entitäten werden über GraphQL geschrieben; die REST-Oberfläche des Asset Repository hat keinen direkten Entitäts-Schreibzugriff. Der Import-Job (POST {tenantId}/v1/Models/ImportRt) wendet dieselbe Regel mit derselben Meldungsnummer 6384 an, wenn er im Namen des auslösenden Benutzers läuft: Eine Datei, die eine gesperrte Entität überschreiben würde, schlägt als Ganzes fehl, das Job-Ergebnis listet jede betroffene ckTypeId@rtId, und es wird nichts geschrieben (AB#6392). Der auslösende Aufrufer wird mit dem Import-Job mitgeführt; für diesen Schutz ist daher keine zusätzliche Beschränkung von ImportRt auf Administratoren nötig.

Wer betroffen ist​

AufruferGesperrte Entität eines geschützten Typs
Mandanten-Benutzer, auch mit Schreibberechtigung für den TypAbgewiesen mit BLUEPRINT_LOCKED
Pipeline-Knoten mit Identity: ServiceAccountAbgewiesen: Ein konfiguriertes Service-Konto wird wie ein Benutzer behandelt. Eine Pipeline, die produktseitige Entitäten schreiben muss, benötigt Identity: System
System-Kontext: Blueprint-Installation, -Update und erzwungenes erneutes Anwenden, Identity: System-Pipelines, interne DiensteErlaubt
Entsperrte Entität (rtBlueprintLocked ist false oder fehlt) oder ein nicht geschützter TypErlaubt, nichts ändert sich

Läuft die Datenrichtlinie im Modus AuditOnly, gelingt die Änderung, und statt des Fehlers wird das Audit-Ereignis DataPermissions.BlueprintLockViolation veröffentlicht.

Fehler im Code behandeln​

TypeScript/JavaScript-Beispiel​

const response = await client.query({ query: GET_ENERGY_METERS });

if (response.errors) {
for (const error of response.errors) {
console.error(`Error: ${error.message}`);

if (error.extensions?.code === 'ENTITY_NOT_FOUND') {
// Handle missing entity
} else if (error.extensions?.code === 'FORBIDDEN') {
// Handle permission error
} else if (error.extensions?.code === 'BLUEPRINT_LOCKED') {
// The entity is owned by the product: show it read-only
console.warn(`Locked by blueprint: ${error.extensions.rtId}`);
}
}
}

if (response.data) {
// Process successful data
}

Auf partiellen Erfolg prüfen​

const response = await client.mutate({
mutation: CREATE_ENTITIES,
variables: { entities: [...] }
});

// Check if any entities were created despite errors
const createdEntities = response.data?.runtime?.myEntities?.create ?? [];
const failedCount = entities.length - createdEntities.length;

if (response.errors && failedCount > 0) {
console.warn(`${failedCount} entities failed to create`);
}

Validierungsfehler​

Validierungsfehler enthalten typischerweise Details darüber, welches Feld fehlgeschlagen ist und warum:

{
"errors": [
{
"message": "Validation failed",
"extensions": {
"code": "VALIDATION_ERROR",
"validationErrors": [
{
"field": "voltage",
"message": "Value must be between 0 and 500"
},
{
"field": "name",
"message": "Name must not be empty"
}
]
}
}
]
}

Best Practices​

  1. Prüfen Sie stets auf Fehler: Selbst erfolgreich aussehende Antworten können partielle Fehler enthalten
  2. Verwenden Sie Fehlercodes: Gleichen Sie mit extensions.code ab, anstatt Fehlermeldungen zu parsen
  3. Behandeln Sie partielle Daten: Verarbeiten Sie alle gültigen Daten, die zusammen mit Fehlern zurückgegeben werden
  4. Protokollieren Sie Fehlerdetails: Nehmen Sie path und extensions zur Fehlersuche in die Logs auf
  5. Benutzerfreundliche Meldungen: Bilden Sie Fehlercodes auf lokalisierte, benutzerseitige Meldungen ab
  6. Transiente Fehler wiederholen: Netzwerk- oder Timeout-Fehler können bei einem erneuten Versuch erfolgreich sein