diff --git a/alfa-client/apps/alfa/src/styles/material/_formfield.scss b/alfa-client/apps/alfa/src/styles/material/_formfield.scss
index 2e22e8b8ecf4a04dc2810a38022639466d2f3962..5cd264736c1e1a67ae882b08427d5c3239d0e895 100644
--- a/alfa-client/apps/alfa/src/styles/material/_formfield.scss
+++ b/alfa-client/apps/alfa/src/styles/material/_formfield.scss
@@ -26,11 +26,12 @@ ozgcloud-fixed-dialog {
 
 body.dark {
   mat-form-field {
-    --mdc-theme-error: red;
-    --mdc-filled-text-field-error-focus-label-text-color: red;
-    --mdc-outlined-text-field-error-focus-label-text-color: red;
-    --mdc-filled-text-field-error-label-text-color: red;
-    --mdc-outlined-text-field-error-label-text-color: red;
-    --mdc-filled-text-field-disabled-active-indicator-color: red;
+    --mdc-theme-error: theme('colors.error');
+    --mat-form-field-error-text-color: theme('colors.error');
+    --mdc-filled-text-field-error-focus-label-text-color: theme('colors.error');
+    --mdc-outlined-text-field-error-focus-label-text-color: theme('colors.error');
+    --mdc-filled-text-field-error-label-text-color: theme('colors.error');
+    --mdc-outlined-text-field-error-label-text-color: theme('colors.error');
+    --mdc-filled-text-field-disabled-active-indicator-color: theme('colors.error');
   }
 }
diff --git a/alfa-client/libs/admin-settings/src/lib/postfach/postfach-container/postfach-form/postfach-form.component.spec.ts b/alfa-client/libs/admin-settings/src/lib/postfach/postfach-container/postfach-form/postfach-form.component.spec.ts
index f786c3e04a73e2bc719cacf654aaf0c01d77039d..f3e6c68f3f15f51d766224ea4add00605a4e05be 100644
--- a/alfa-client/libs/admin-settings/src/lib/postfach/postfach-container/postfach-form/postfach-form.component.spec.ts
+++ b/alfa-client/libs/admin-settings/src/lib/postfach/postfach-container/postfach-form/postfach-form.component.spec.ts
@@ -175,7 +175,7 @@ describe('PostfachFormComponent', () => {
     function createProblemDetailForAbsenderName(): ProblemDetail {
       return {
         ...createProblemDetail(),
-        'invalid-params': [{ ...createInvalidParam(), name: 'settingBody.absender.name' }],
+        invalidParams: [{ ...createInvalidParam(), name: 'settingBody.absender.name' }],
       };
     }
 
diff --git a/alfa-client/libs/binary-file-shared/src/lib/binary-file.service.spec.ts b/alfa-client/libs/binary-file-shared/src/lib/binary-file.service.spec.ts
index 9d69ae78a151079401a9d94caceff99e8c980675..328960de1f9b9a87f8442595ad8b609f339f9da8 100644
--- a/alfa-client/libs/binary-file-shared/src/lib/binary-file.service.spec.ts
+++ b/alfa-client/libs/binary-file-shared/src/lib/binary-file.service.spec.ts
@@ -262,7 +262,7 @@ describe('BinaryFileService', () => {
         service.handleSnackBar(buildUnprocessableEntityErrorResponse(), true);
 
         expect(snackBarService.showError).toHaveBeenCalledWith(
-          VALIDATION_MESSAGES[ValidationMessageCode.VALIDATION_FIELD_FILE_SIZE_EXCEEDED],
+          VALIDATION_MESSAGES[ValidationMessageCode.FIELD_FILE_SIZE_EXCEEDED],
         );
       });
 
@@ -274,7 +274,7 @@ describe('BinaryFileService', () => {
 
       it('should not call snackbarService if not file size exceeded error', () => {
         service.handleSnackBar(
-          buildUnprocessableEntityErrorResponse(ValidationMessageCode.VALIDATION_FIELD_EMPTY),
+          buildUnprocessableEntityErrorResponse(ValidationMessageCode.FIELD_EMPTY),
           true,
         );
 
@@ -283,15 +283,15 @@ describe('BinaryFileService', () => {
     });
 
     function buildUnprocessableEntityErrorResponse(
-      validationMessageCode: ValidationMessageCode = ValidationMessageCode.VALIDATION_FIELD_FILE_SIZE_EXCEEDED,
+      validationMessageCode: ValidationMessageCode = ValidationMessageCode.FIELD_FILE_SIZE_EXCEEDED,
     ): HttpErrorResponse {
       return <HttpErrorResponse>{
         status: 422,
         error: {
-          issues: [
+          invalidParams: [
             {
-              messageCode: validationMessageCode,
-              parameters: [],
+              reason: validationMessageCode,
+              constraintParameters: [],
             },
           ],
         },
diff --git a/alfa-client/libs/binary-file-shared/src/lib/binary-file.service.ts b/alfa-client/libs/binary-file-shared/src/lib/binary-file.service.ts
index bb6592cb76931ff30edca949cc28a864686ecfce..57773cccbfa61d4dab2af4984a88d6d3f9cf7b14 100644
--- a/alfa-client/libs/binary-file-shared/src/lib/binary-file.service.ts
+++ b/alfa-client/libs/binary-file-shared/src/lib/binary-file.service.ts
@@ -29,7 +29,7 @@ import {
   createEmptyStateResource,
   createErrorStateResource,
   createStateResource,
-  getMessageForIssue,
+  getMessageForInvalidParam,
   isNotNil,
   isUnprocessableEntity,
   isValidationFieldFileSizeExceedError,
@@ -90,7 +90,9 @@ export class BinaryFileService {
 
   handleSnackBar(error: HttpErrorResponse, showValidationErrorSnackBar: boolean) {
     if (showValidationErrorSnackBar && isValidationFieldFileSizeExceedError(error.error)) {
-      this.snackbarService.showError(getMessageForIssue(EMPTY_STRING, error.error.issues[0]));
+      this.snackbarService.showError(
+        getMessageForInvalidParam(EMPTY_STRING, error.error.invalidParams[0]),
+      );
     }
   }
 
diff --git a/alfa-client/libs/design-component/src/lib/form/formcontrol-editor.abstract.component.ts b/alfa-client/libs/design-component/src/lib/form/formcontrol-editor.abstract.component.ts
index a023a009d1780be33395159d25234da39285f745..cb0f3f5842b32a3ce76321d194097c9a2f64229a 100644
--- a/alfa-client/libs/design-component/src/lib/form/formcontrol-editor.abstract.component.ts
+++ b/alfa-client/libs/design-component/src/lib/form/formcontrol-editor.abstract.component.ts
@@ -21,7 +21,7 @@
  * Die sprachspezifischen Genehmigungen und Beschränkungen
  * unter der Lizenz sind dem Lizenztext zu entnehmen.
  */
-import { Issue } from '@alfa-client/tech-shared';
+import { InvalidParam } from '@alfa-client/tech-shared';
 import { Component, OnDestroy, OnInit, Optional, Self } from '@angular/core';
 import { ControlValueAccessor, NgControl, UntypedFormControl } from '@angular/forms';
 import { isEmpty } from 'lodash-es';
@@ -89,9 +89,11 @@ export abstract class FormControlEditorAbstractComponent
     }
   }
 
-  get issues(): Issue[] {
+  get invalidParams(): InvalidParam[] {
     return this.fieldControl.errors ?
-        Object.keys(this.fieldControl.errors).map((key) => <Issue>this.fieldControl.errors[key])
+        Object.keys(this.fieldControl.errors).map(
+          (key) => <InvalidParam>this.fieldControl.errors[key],
+        )
       : [];
   }
 }
diff --git a/alfa-client/libs/design-component/src/lib/form/text-editor/text-editor.component.html b/alfa-client/libs/design-component/src/lib/form/text-editor/text-editor.component.html
index 544b9312b03adba3e0e097e8eba8a20751e5b013..9252326a5bdcc9d9c25ec164981bd0e24915bafa 100644
--- a/alfa-client/libs/design-component/src/lib/form/text-editor/text-editor.component.html
+++ b/alfa-client/libs/design-component/src/lib/form/text-editor/text-editor.component.html
@@ -10,7 +10,7 @@
 >
   <ods-validation-error
     error
-    [issues]="issues"
+    [invalidParams]="invalidParams"
     [label]="label"
     [attr.data-test-id]="(label | convertForDataTest) + '-text-editor-error'"
   ></ods-validation-error>
diff --git a/alfa-client/libs/design-component/src/lib/form/text-editor/text-editor.component.ts b/alfa-client/libs/design-component/src/lib/form/text-editor/text-editor.component.ts
index c78a7554800ed6f61eb9d189617811e7f9d0490a..c40849cf31e2279a3727527898213567bab07c4c 100644
--- a/alfa-client/libs/design-component/src/lib/form/text-editor/text-editor.component.ts
+++ b/alfa-client/libs/design-component/src/lib/form/text-editor/text-editor.component.ts
@@ -26,6 +26,6 @@ export class TextEditorComponent extends FormControlEditorAbstractComponent {
   @Input() focus: boolean = false;
 
   get variant(): string {
-    return this.issues.length > 0 ? 'error' : 'default';
+    return this.invalidParams.length > 0 ? 'error' : 'default';
   }
 }
diff --git a/alfa-client/libs/design-component/src/lib/form/textarea-editor/textarea-editor.component.html b/alfa-client/libs/design-component/src/lib/form/textarea-editor/textarea-editor.component.html
index 5f3959bd34260ac44c11db6a108f24583986b9b0..c27f425a3f9ca703f85b9961a8c87175a50a0a9f 100644
--- a/alfa-client/libs/design-component/src/lib/form/textarea-editor/textarea-editor.component.html
+++ b/alfa-client/libs/design-component/src/lib/form/textarea-editor/textarea-editor.component.html
@@ -10,7 +10,7 @@
 >
   <ods-validation-error
     error
-    [issues]="issues"
+    [invalidParams]="invalidParams"
     [label]="label"
     [attr.data-test-id]="(label | convertForDataTest) + '-textarea-editor-error'"
   ></ods-validation-error>
diff --git a/alfa-client/libs/design-component/src/lib/form/textarea-editor/textarea-editor.component.ts b/alfa-client/libs/design-component/src/lib/form/textarea-editor/textarea-editor.component.ts
index f78ee2c938fdb89b91a17060ba862ecadcff04aa..a47b955192b12c4a9ce1379062cd16543e455e2a 100644
--- a/alfa-client/libs/design-component/src/lib/form/textarea-editor/textarea-editor.component.ts
+++ b/alfa-client/libs/design-component/src/lib/form/textarea-editor/textarea-editor.component.ts
@@ -26,6 +26,6 @@ export class TextareaEditorComponent extends FormControlEditorAbstractComponent
   @Input() focus: boolean = false;
 
   get variant(): string {
-    return this.issues.length > 0 ? 'error' : 'default';
+    return this.invalidParams.length > 0 ? 'error' : 'default';
   }
 }
diff --git a/alfa-client/libs/design-component/src/lib/form/validation-error/validation-error.component.html b/alfa-client/libs/design-component/src/lib/form/validation-error/validation-error.component.html
index 703f757c2b17228e8cdfb7d158a7bb7e6a058a93..28ffaaac9b7880787146c5091eceedee3d2a662e 100644
--- a/alfa-client/libs/design-component/src/lib/form/validation-error/validation-error.component.html
+++ b/alfa-client/libs/design-component/src/lib/form/validation-error/validation-error.component.html
@@ -1,3 +1,3 @@
-<ng-container *ngFor="let issue of issues"
-  ><ods-error-message [text]="message(issue)"></ods-error-message
+<ng-container *ngFor="let invalidParam of invalidParams"
+  ><ods-error-message [text]="message(invalidParam)"></ods-error-message
 ></ng-container>
diff --git a/alfa-client/libs/design-component/src/lib/form/validation-error/validation-error.component.spec.ts b/alfa-client/libs/design-component/src/lib/form/validation-error/validation-error.component.spec.ts
index 6abe6133bddfc36ca6ca42e2aa28d049fa96ef4d..845bf47eb456d09d581f97fae71493c8808729ac 100644
--- a/alfa-client/libs/design-component/src/lib/form/validation-error/validation-error.component.spec.ts
+++ b/alfa-client/libs/design-component/src/lib/form/validation-error/validation-error.component.spec.ts
@@ -1,6 +1,7 @@
-import { getMessageForIssue } from '@alfa-client/tech-shared';
+import { getMessageForInvalidParam, InvalidParam } from '@alfa-client/tech-shared';
 import { ComponentFixture, TestBed } from '@angular/core/testing';
-import { createIssue } from 'libs/tech-shared/test/error';
+import { ValidationMessageCode } from 'libs/tech-shared/src/lib/validation/tech.validation.messages';
+import { createInvalidParam } from 'libs/tech-shared/test/error';
 import { ValidationErrorComponent } from './validation-error.component';
 
 describe('ValidationErrorComponent', () => {
@@ -21,32 +22,29 @@ describe('ValidationErrorComponent', () => {
     expect(component).toBeTruthy();
   });
 
-  describe('get message for issue', () => {
+  describe('get message from invalidParam', () => {
     const fieldLabel: string = 'Field Label';
+    const invalidParam: InvalidParam = {
+      ...createInvalidParam(),
+      reason: ValidationMessageCode.FIELD_SIZE,
+    };
 
-    it('should return message', () => {
-      const msg: string = getMessageForIssue(fieldLabel, {
-        ...createIssue(),
-        messageCode: 'validation_field_size',
-      });
+    it('should contain', () => {
+      const msg: string = getMessageForInvalidParam(fieldLabel, invalidParam);
 
       expect(msg).toContain('muss mindestens');
     });
 
     it('should set field label', () => {
-      const msg: string = getMessageForIssue(fieldLabel, {
-        ...createIssue(),
-        messageCode: 'validation_field_size',
-      });
+      const msg: string = getMessageForInvalidParam(fieldLabel, invalidParam);
 
       expect(msg).toContain(fieldLabel);
     });
 
     it('should replace min param', () => {
-      const msg: string = getMessageForIssue(fieldLabel, {
-        ...createIssue(),
-        messageCode: 'validation_field_size',
-        parameters: [{ name: 'min', value: '3' }],
+      const msg: string = getMessageForInvalidParam(fieldLabel, {
+        ...invalidParam,
+        constraintParameters: [{ name: 'min', value: '3' }],
       });
 
       expect(msg).toContain('3');
diff --git a/alfa-client/libs/design-component/src/lib/form/validation-error/validation-error.component.ts b/alfa-client/libs/design-component/src/lib/form/validation-error/validation-error.component.ts
index d47b675b4984616c8ff76acaa04d3c73ebafad42..4d8a67a6e5f9ee9d39a99c9fe5fd97fe6136fe2c 100644
--- a/alfa-client/libs/design-component/src/lib/form/validation-error/validation-error.component.ts
+++ b/alfa-client/libs/design-component/src/lib/form/validation-error/validation-error.component.ts
@@ -1,4 +1,4 @@
-import { Issue, getMessageForIssue } from '@alfa-client/tech-shared';
+import { InvalidParam, getMessageForInvalidParam } from '@alfa-client/tech-shared';
 import { CommonModule } from '@angular/common';
 import { Component, Input } from '@angular/core';
 import { ErrorMessageComponent } from '@ods/system';
@@ -11,9 +11,9 @@ import { ErrorMessageComponent } from '@ods/system';
 })
 export class ValidationErrorComponent {
   @Input() label: string;
-  @Input() issues: Issue[];
+  @Input() invalidParams: InvalidParam[];
 
-  public message(issue: Issue): string {
-    return getMessageForIssue(this.label, issue);
+  public message(invalidParam: InvalidParam): string {
+    return getMessageForInvalidParam(this.label, invalidParam);
   }
 }
diff --git a/alfa-client/libs/navigation/src/lib/build-info/build-info.component.html b/alfa-client/libs/navigation/src/lib/build-info/build-info.component.html
index 3befc6c17ff6c1c67843bb0969acfb0ed2ce4ef3..41cce668006927fdd81db4f1c49e8eaca49358cd 100644
--- a/alfa-client/libs/navigation/src/lib/build-info/build-info.component.html
+++ b/alfa-client/libs/navigation/src/lib/build-info/build-info.component.html
@@ -30,6 +30,6 @@
     <span data-test-id="build-time">{{ buildTime }}</span>
   </ng-container>
 </p>
-<p *ngIf="isNotProduction" data-test-id="not-production-text" class="test-environment">
+<p *ngIf="isNotProduction" data-test-id="not-production-text" class="test-environment text-error">
   Achtung Testumgebung
 </p>
diff --git a/alfa-client/libs/navigation/src/lib/build-info/build-info.component.scss b/alfa-client/libs/navigation/src/lib/build-info/build-info.component.scss
index ec3f82e9c13c393371836db8fecfca6ecc6467d5..fbbb84ab523edbd1ed3fd2d158e9465a5df9342b 100644
--- a/alfa-client/libs/navigation/src/lib/build-info/build-info.component.scss
+++ b/alfa-client/libs/navigation/src/lib/build-info/build-info.component.scss
@@ -61,5 +61,4 @@ p {
   margin-right: $navigation-height + $header-height;
   letter-spacing: 0.42em;
   text-transform: uppercase;
-  color: #ff0000;
 }
diff --git a/alfa-client/libs/navigation/src/lib/header-container/header/header.component.html b/alfa-client/libs/navigation/src/lib/header-container/header/header.component.html
index 3ef7590196924bd350d246c4b084c71a1cc7cdd3..100cd3141dbcb8562608433313d8cdf30c0af56b 100644
--- a/alfa-client/libs/navigation/src/lib/header-container/header/header.component.html
+++ b/alfa-client/libs/navigation/src/lib/header-container/header/header.component.html
@@ -30,7 +30,7 @@
   <div class="middle">
     <alfa-vorgang-search-container></alfa-vorgang-search-container>
   </div>
-  <div class="right">
+  <div class="flex items-center text-ozggray-800 dark:text-ozggray-300">
     <alfa-help-menu
       [apiRootStateResource]="apiRootStateResource"
       data-test-id="help-menu"
diff --git a/alfa-client/libs/navigation/src/lib/header-container/header/header.component.scss b/alfa-client/libs/navigation/src/lib/header-container/header/header.component.scss
index 167169bea4acdf42c9032a84041bf48006b45809..4e6bde87b4b462a01803569bc823015ce6b9f535 100644
--- a/alfa-client/libs/navigation/src/lib/header-container/header/header.component.scss
+++ b/alfa-client/libs/navigation/src/lib/header-container/header/header.component.scss
@@ -53,9 +53,3 @@ header {
     min-width: 240px;
   }
 }
-
-.right {
-  color: $grey;
-  display: flex;
-  align-items: center;
-}
diff --git a/alfa-client/libs/postfach/src/lib/postfach-mail-list-container/postfach-mail-list/postfach-mail/outgoing-mail/outgoing-mail-error-container/outgoing-mail-error/outgoing-mail-error.component.html b/alfa-client/libs/postfach/src/lib/postfach-mail-list-container/postfach-mail-list/postfach-mail/outgoing-mail/outgoing-mail-error-container/outgoing-mail-error/outgoing-mail-error.component.html
index ba6a2c55856a17a9780c64cbb785fd4ea54f96b8..ba91c347f14db1b8a045f6f1c19ee795f3618cb7 100644
--- a/alfa-client/libs/postfach/src/lib/postfach-mail-list-container/postfach-mail-list/postfach-mail/outgoing-mail/outgoing-mail-error-container/outgoing-mail-error/outgoing-mail-error.component.html
+++ b/alfa-client/libs/postfach/src/lib/postfach-mail-list-container/postfach-mail-list/postfach-mail/outgoing-mail/outgoing-mail-error-container/outgoing-mail-error/outgoing-mail-error.component.html
@@ -29,7 +29,7 @@
   class="mail-send-error"
 >
   <span data-test-id="mail-send-error-text">{{ message }}</span>
-  <mat-icon data-test-id="mail-send-error-icon" class="mail-send-error__icon mat-icon-error"
+  <mat-icon data-test-id="mail-send-error-icon" class="mail-send-error__icon text-error"
     >error_outline_white</mat-icon
   >
 </div>
diff --git a/alfa-client/libs/postfach/src/lib/postfach-mail-list-container/postfach-mail-list/postfach-mail/outgoing-mail/outgoing-mail-error-container/outgoing-mail-error/outgoing-mail-error.component.scss b/alfa-client/libs/postfach/src/lib/postfach-mail-list-container/postfach-mail-list/postfach-mail/outgoing-mail/outgoing-mail-error-container/outgoing-mail-error/outgoing-mail-error.component.scss
index d62fb722598b2db40eaa946e2e79722616ecaf0d..aadb9a11f319d4c53e79987a439f2647db86c7f8 100644
--- a/alfa-client/libs/postfach/src/lib/postfach-mail-list-container/postfach-mail-list/postfach-mail/outgoing-mail/outgoing-mail-error-container/outgoing-mail-error/outgoing-mail-error.component.scss
+++ b/alfa-client/libs/postfach/src/lib/postfach-mail-list-container/postfach-mail-list/postfach-mail/outgoing-mail/outgoing-mail-error-container/outgoing-mail-error/outgoing-mail-error.component.scss
@@ -25,10 +25,6 @@
 @use '@angular/material' as mat;
 @import 'variables';
 
-.mat-icon-error {
-  color: mat.get-color-from-palette($warnPalette);
-}
-
 .mail-send-error {
   display: flex;
   align-items: center;
diff --git a/alfa-client/libs/tech-shared/src/index.ts b/alfa-client/libs/tech-shared/src/index.ts
index 64e34b9ffcb66244bb7687070f685ed6090b4950..6447da0179658e13795f1dbe8bfa8f0df2adeda3 100644
--- a/alfa-client/libs/tech-shared/src/index.ts
+++ b/alfa-client/libs/tech-shared/src/index.ts
@@ -33,6 +33,7 @@ export * from './lib/message-code';
 export * from './lib/ngrx/actions';
 export * from './lib/pipe/convert-api-error-to-error-messages.pipe';
 export * from './lib/pipe/convert-for-data-test.pipe';
+export * from './lib/pipe/convert-problem-detail-to-error-messages.pipe';
 export * from './lib/pipe/convert-to-boolean.pipe';
 export * from './lib/pipe/enum-to-label.pipe';
 export * from './lib/pipe/file-size.pipe';
diff --git a/alfa-client/libs/tech-shared/src/lib/pipe/convert-problem-detail-to-error-messages.pipe.spec.ts b/alfa-client/libs/tech-shared/src/lib/pipe/convert-problem-detail-to-error-messages.pipe.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..ffef78f2195217763693fbd09abf727915afac23
--- /dev/null
+++ b/alfa-client/libs/tech-shared/src/lib/pipe/convert-problem-detail-to-error-messages.pipe.spec.ts
@@ -0,0 +1,42 @@
+import { createInvalidParam, createProblemDetail } from '../../../test/error';
+import { InvalidParam, ProblemDetail } from '../tech.model';
+import { ValidationMessageCode } from '../validation/tech.validation.messages';
+import * as TechValidationUtil from '../validation/tech.validation.util';
+import { ConvertProblemDetailToErrorMessagesPipe } from './convert-problem-detail-to-error-messages.pipe';
+
+describe('convertProblemDetailToErrorMessages', () => {
+  const pipe = new ConvertProblemDetailToErrorMessagesPipe();
+
+  it('create an instance', () => {
+    expect(pipe).toBeTruthy();
+  });
+
+  describe('transform', () => {
+    const getMessageForInvalidParam = jest.spyOn(TechValidationUtil, 'getMessageForInvalidParam');
+
+    it('should not call getMessageForInvalidParam', () => {
+      pipe.transform(null);
+
+      expect(getMessageForInvalidParam).not.toHaveBeenCalled();
+    });
+
+    it('should call getMessageForInvalidParam', () => {
+      pipe.transform(createProblemDetail());
+
+      expect(getMessageForInvalidParam).toHaveBeenCalled();
+    });
+
+    it('should return array of error messages', () => {
+      const expectedErrorMessage = 'Bitte  ausfüllen';
+      const invalidParam: InvalidParam = {
+        ...createInvalidParam(),
+        reason: ValidationMessageCode.FIELD_EMPTY,
+      };
+      const problemDetail: ProblemDetail = createProblemDetail([invalidParam]);
+
+      const errorMessages: string[] = pipe.transform(problemDetail);
+
+      expect(errorMessages).toEqual([expectedErrorMessage]);
+    });
+  });
+});
diff --git a/alfa-client/libs/tech-shared/src/lib/pipe/convert-problem-detail-to-error-messages.pipe.ts b/alfa-client/libs/tech-shared/src/lib/pipe/convert-problem-detail-to-error-messages.pipe.ts
new file mode 100644
index 0000000000000000000000000000000000000000..437483a923c7f85353b96a745a2c24e1cc88e0fb
--- /dev/null
+++ b/alfa-client/libs/tech-shared/src/lib/pipe/convert-problem-detail-to-error-messages.pipe.ts
@@ -0,0 +1,17 @@
+import { Pipe, PipeTransform } from '@angular/core';
+import { isNil } from 'lodash-es';
+import { InvalidParam, ProblemDetail } from '../tech.model';
+import { EMPTY_STRING } from '../tech.util';
+import { getMessageForInvalidParam } from '../validation/tech.validation.util';
+
+@Pipe({ name: 'convertProblemDetailToErrorMessages' })
+export class ConvertProblemDetailToErrorMessagesPipe implements PipeTransform {
+  transform(value: ProblemDetail) {
+    if (isNil(value)) {
+      return [];
+    }
+    return value.invalidParams.map((invalidParam: InvalidParam) =>
+      getMessageForInvalidParam(EMPTY_STRING, invalidParam),
+    );
+  }
+}
diff --git a/alfa-client/libs/tech-shared/src/lib/service/formservice.abstract.spec.ts b/alfa-client/libs/tech-shared/src/lib/service/formservice.abstract.spec.ts
index 1472e6fe3c880b33faeaf14e875f6973dde18a73..ee4a624cb890cbf0da636f80ae01f1aeb7fdc616 100644
--- a/alfa-client/libs/tech-shared/src/lib/service/formservice.abstract.spec.ts
+++ b/alfa-client/libs/tech-shared/src/lib/service/formservice.abstract.spec.ts
@@ -25,12 +25,12 @@ import { CommandResource } from '@alfa-client/command-shared';
 import { UntypedFormBuilder, UntypedFormControl, UntypedFormGroup } from '@angular/forms';
 import { Resource } from '@ngxp/rest';
 import { cold } from 'jest-marbles';
-import { createApiError, createInvalidParam, createIssue, createProblemDetail } from 'libs/tech-shared/test/error';
+import { createInvalidParam, createProblemDetail } from 'libs/tech-shared/test/error';
 import { Observable, of } from 'rxjs';
 import { AbstractFormService } from './formservice.abstract';
 
 import { createEmptyStateResource, createErrorStateResource, createStateResource, StateResource } from '../resource/resource.util';
-import { ApiError, HttpError, InvalidParam, Issue, ProblemDetail } from '../tech.model';
+import { HttpError, InvalidParam, ProblemDetail } from '../tech.model';
 
 import { createCommandResource } from '../../../../command-shared/test/command';
 import * as ValidationUtil from '../validation/tech.validation.util';
@@ -47,16 +47,16 @@ describe('AbstractFormService', () => {
   });
 
   describe('submit', () => {
-    describe('with api error', () => {
-      const stateResourceWithError: StateResource<ApiError> =
-        createErrorStateResource(createApiError());
+    describe('with ProblemDetail', () => {
+      const stateResourceWithError: StateResource<ProblemDetail> =
+        createErrorStateResource(createProblemDetail());
 
       beforeEach(() => {
         TestFormService.SUBMIT_OBSERVABLE = () => of(stateResourceWithError);
         formService.handleResponse = jest.fn((stateResource) => stateResource);
       });
 
-      it('should call handle response for api error', (done) => {
+      it('should call handle response for ProblemDetail', (done) => {
         formService.submit().subscribe(() => {
           expect(formService.handleResponse).toHaveBeenCalledWith(stateResourceWithError);
           done();
@@ -97,8 +97,8 @@ describe('AbstractFormService', () => {
   });
 
   describe('handleResponse', () => {
-    const apiError: ApiError = createApiError();
-    const stateResource: StateResource<CommandResource> = createErrorStateResource(apiError);
+    const problemDetail: ProblemDetail = createProblemDetail();
+    const stateResource: StateResource<CommandResource> = createErrorStateResource(problemDetail);
 
     beforeEach(() => {
       formService.handleError = jest.fn();
@@ -107,7 +107,7 @@ describe('AbstractFormService', () => {
     it('should handleError on validation error', () => {
       formService.handleResponse({ ...stateResource, loading: false });
 
-      expect(formService.handleError).toHaveBeenCalledWith(apiError);
+      expect(formService.handleError).toHaveBeenCalledWith(problemDetail);
     });
 
     it('should return stateresource while loading', () => {
@@ -129,34 +129,6 @@ describe('AbstractFormService', () => {
 
       expect(formService.setErrorByProblemDetail).toHaveBeenCalledWith(problemDetail);
     });
-
-    it('should set api error', () => {
-      formService.setErrorByApiError = jest.fn();
-      const apiError: ApiError = createApiError();
-
-      formService.handleError(apiError);
-
-      expect(formService.setErrorByApiError).toHaveBeenCalledWith(apiError);
-    });
-  });
-
-  describe('set error by api error', () => {
-    const issue: Issue = createIssue();
-    const apiError: ApiError = createApiError([issue]);
-
-    it('should call setIssueValidationError', () => {
-      const setInvalidParamValidationErrorSpy: jest.SpyInstance<void> = jest
-        .spyOn(ValidationUtil, 'setIssueValidationError')
-        .mockImplementation();
-
-      formService.setErrorByApiError(apiError);
-
-      expect(setInvalidParamValidationErrorSpy).toHaveBeenCalledWith(
-        formService.form,
-        issue,
-        TestFormService.PATH_PREFIX,
-      );
-    });
   });
 
   describe('set error by problem detail', () => {
diff --git a/alfa-client/libs/tech-shared/src/lib/service/formservice.abstract.ts b/alfa-client/libs/tech-shared/src/lib/service/formservice.abstract.ts
index ab647437a8483fb73bccc4fa0e4d083ef8c48cde..1af38f9f8065ae4685acb7326d1a65b3d88fcd69 100644
--- a/alfa-client/libs/tech-shared/src/lib/service/formservice.abstract.ts
+++ b/alfa-client/libs/tech-shared/src/lib/service/formservice.abstract.ts
@@ -28,16 +28,16 @@ import { isNil } from 'lodash-es';
 import { identity, Observable, OperatorFunction } from 'rxjs';
 import { map } from 'rxjs/operators';
 import { hasStateResourceError, StateResource } from '../resource/resource.util';
-import { ApiError, HttpError, InvalidParam, Issue, ProblemDetail } from '../tech.model';
+import { HttpError, InvalidParam, ProblemDetail } from '../tech.model';
 import { isNotUndefined } from '../tech.util';
-import { setInvalidParamValidationError, setIssueValidationError } from '../validation/tech.validation.util';
+import { setInvalidParamValidationError } from '../validation/tech.validation.util';
 
 export abstract class AbstractFormService {
   form: UntypedFormGroup;
   pathPrefix: string;
   source: any;
 
-  private readonly PROBLEM_DETAIL_INVALID_PARAMS_KEY: string = 'invalid-params';
+  private readonly PROBLEM_DETAIL_INVALID_PARAMS_KEY: string = 'invalidParams';
 
   constructor(public formBuilder: UntypedFormBuilder) {
     this.form = this.initForm();
@@ -65,28 +65,15 @@ export abstract class AbstractFormService {
   }
 
   handleError(error: HttpError): void {
-    if (this.isApiError(error)) {
-      this.setErrorByApiError(<ApiError>error);
-    }
-    if (this.isProblemDetail(error)) {
+    if (this.hasError(error)) {
       this.setErrorByProblemDetail(<ProblemDetail>error);
     }
   }
 
-  private isApiError(error: HttpError): boolean {
-    return isNotUndefined((<ApiError>error).issues);
-  }
-
-  private isProblemDetail(error: HttpError): boolean {
+  private hasError(error: HttpError): boolean {
     return isNotUndefined((<ProblemDetail>error)[this.PROBLEM_DETAIL_INVALID_PARAMS_KEY]);
   }
 
-  setErrorByApiError(apiError: ApiError): void {
-    apiError.issues.forEach((issue: Issue) =>
-      setIssueValidationError(this.form, issue, this.getPathPrefix()),
-    );
-  }
-
   setErrorByProblemDetail(error: ProblemDetail): void {
     error[this.PROBLEM_DETAIL_INVALID_PARAMS_KEY].forEach((invalidParam: InvalidParam) => {
       setInvalidParamValidationError(this.form, invalidParam, this.getPathPrefix());
diff --git a/alfa-client/libs/tech-shared/src/lib/tech-shared.module.ts b/alfa-client/libs/tech-shared/src/lib/tech-shared.module.ts
index 331031b298487fcfa77df7c10041a33cfedec7bb..a91930ffa732c82e0be57db7f18516b24eb393c9 100644
--- a/alfa-client/libs/tech-shared/src/lib/tech-shared.module.ts
+++ b/alfa-client/libs/tech-shared/src/lib/tech-shared.module.ts
@@ -29,6 +29,7 @@ import { HttpXsrfInterceptor } from './interceptor/http-xsrf.interceptor';
 import { XhrInterceptor } from './interceptor/xhr.interceptor';
 import { ConvertApiErrorToErrorMessagesPipe } from './pipe/convert-api-error-to-error-messages.pipe';
 import { ConvertForDataTestPipe } from './pipe/convert-for-data-test.pipe';
+import { ConvertProblemDetailToErrorMessagesPipe } from './pipe/convert-problem-detail-to-error-messages.pipe';
 import { ConvertToBooleanPipe } from './pipe/convert-to-boolean.pipe';
 import { EnumToLabelPipe } from './pipe/enum-to-label.pipe';
 import { FileSizePlainPipe } from './pipe/file-size-plain.pipe';
@@ -69,6 +70,7 @@ import { ToTrafficLightPipe } from './pipe/to-traffic-light.pipe';
     GetUrlPipe,
     ConvertToBooleanPipe,
     ConvertApiErrorToErrorMessagesPipe,
+    ConvertProblemDetailToErrorMessagesPipe,
   ],
   exports: [
     FormatToPrettyDatePipe,
@@ -90,6 +92,7 @@ import { ToTrafficLightPipe } from './pipe/to-traffic-light.pipe';
     GetUrlPipe,
     ConvertToBooleanPipe,
     ConvertApiErrorToErrorMessagesPipe,
+    ConvertProblemDetailToErrorMessagesPipe,
   ],
   providers: [
     {
diff --git a/alfa-client/libs/tech-shared/src/lib/tech.model.ts b/alfa-client/libs/tech-shared/src/lib/tech.model.ts
index c85852676e5184152aa17856cca07bd33b3a3223..869313d09ddd0b5c7703f80ea79f23bf72403e07 100644
--- a/alfa-client/libs/tech-shared/src/lib/tech.model.ts
+++ b/alfa-client/libs/tech-shared/src/lib/tech.model.ts
@@ -47,12 +47,19 @@ export interface ProblemDetail {
   status: HttpStatusCode;
   detail: string;
   instance: string;
-  'invalid-params': InvalidParam[];
+  invalidParams: InvalidParam[];
 }
 
 export interface InvalidParam {
+  constraintParameters: ConstraintParameter[];
   name: string;
   reason: ValidationMessageCode;
+  value: string;
+}
+
+export interface ConstraintParameter {
+  name: string;
+  value: string;
 }
 
 export declare type HttpError = ProblemDetail | ApiError;
diff --git a/alfa-client/libs/tech-shared/src/lib/validation/tech.validation.messages.ts b/alfa-client/libs/tech-shared/src/lib/validation/tech.validation.messages.ts
index 6c71c22768bb5ae231daf6b3522002a9110bda00..82da103d936c9c009cdfb20a9b1e652cf5b41648 100644
--- a/alfa-client/libs/tech-shared/src/lib/validation/tech.validation.messages.ts
+++ b/alfa-client/libs/tech-shared/src/lib/validation/tech.validation.messages.ts
@@ -22,23 +22,31 @@
  * unter der Lizenz sind dem Lizenztext zu entnehmen.
  */
 export enum ValidationMessageCode {
-  VALIDATION_FIELD_FILE_SIZE_EXCEEDED = 'validation_field_file_size_exceeded',
-  VALIDATION_FIELD_EMPTY = 'validation_field_empty',
-  VALIDATION_FIELD_FILE_CONTENT_TYPE_INVALID = 'validation_field_file_content_type_invalid',
+  FIELD_FILE_SIZE_EXCEEDED = 'validation_field_file_size_exceeded',
+  FIELD_EMPTY = 'validation_field_empty',
+  FIELD_SIZE = 'validation_field_size',
+  FIELD_FILE_CONTENT_TYPE_INVALID = 'validation_field_file_content_type_invalid',
+  FIELD_MIN_SIZE = 'validation_field_min_size',
+  FIELD_MAX_SIZE = 'validation_field_max_size',
+  FIELD_DATE_PAST = 'validation_field_date_past',
+  FIELD_INVALID = 'validation_field_invalid',
+  FIELD_DATE_FORMAT_INVALID = 'validation_field_date_format_invalid',
+  FIELD_ASSIGN_BEARBEITER_NOT_EXIST = 'fe_only_validation_bearbeiter_not_exist',
 }
 
 export const VALIDATION_MESSAGES: { [code: string]: string } = {
-  [ValidationMessageCode.VALIDATION_FIELD_EMPTY]: 'Bitte {field} ausfüllen',
-  validation_field_max_size: '{field} darf höchstens {max} Zeichen enthalten',
-  validation_field_min_size: '{field} muss aus mindestens {min} Zeichen bestehen',
-  validation_field_size: '{field} muss mindestens {min} und darf höchstens {max} Zeichen enthalten',
-  validation_field_date_past: 'Das Datum für {field} muss in der Zukunft liegen',
-  validation_field_invalid: 'Bitte {field} korrekt ausfüllen',
-  [ValidationMessageCode.VALIDATION_FIELD_FILE_SIZE_EXCEEDED]:
+  [ValidationMessageCode.FIELD_EMPTY]: 'Bitte {field} ausfüllen',
+  [ValidationMessageCode.FIELD_MAX_SIZE]: '{field} darf höchstens {max} Zeichen enthalten',
+  [ValidationMessageCode.FIELD_MIN_SIZE]: '{field} muss aus mindestens {min} Zeichen bestehen',
+  [ValidationMessageCode.FIELD_SIZE]:
+    '{field} muss mindestens {min} und darf höchstens {max} Zeichen enthalten',
+  [ValidationMessageCode.FIELD_DATE_PAST]: 'Das Datum für {field} muss in der Zukunft liegen',
+  [ValidationMessageCode.FIELD_INVALID]: 'Bitte {field} korrekt ausfüllen',
+  [ValidationMessageCode.FIELD_FILE_SIZE_EXCEEDED]:
     'Anhänge größer {max}{unit} können nicht hinzugefügt werden.',
 
   fe_only_validation_bearbeiter_not_exist: 'Der Bearbeiter existiert nicht',
-  validation_field_date_format_invalid: 'Geben Sie ein gültiges Datum ein',
-  [ValidationMessageCode.VALIDATION_FIELD_FILE_CONTENT_TYPE_INVALID]:
+  [ValidationMessageCode.FIELD_DATE_FORMAT_INVALID]: 'Geben Sie ein gültiges Datum ein',
+  [ValidationMessageCode.FIELD_FILE_CONTENT_TYPE_INVALID]:
     'Erlaubte Dateiendungen: pdf, jpg, png, jpeg',
 };
diff --git a/alfa-client/libs/tech-shared/src/lib/validation/tech.validation.util.spec.ts b/alfa-client/libs/tech-shared/src/lib/validation/tech.validation.util.spec.ts
index 9e0902270b2423a9510872b1a5f15828549eb8d6..bb2e5b51d1be004bced187df35871e16a00d738a 100644
--- a/alfa-client/libs/tech-shared/src/lib/validation/tech.validation.util.spec.ts
+++ b/alfa-client/libs/tech-shared/src/lib/validation/tech.validation.util.spec.ts
@@ -21,23 +21,12 @@
  * Die sprachspezifischen Genehmigungen und Beschränkungen
  * unter der Lizenz sind dem Lizenztext zu entnehmen.
  */
-import {
-  AbstractControl,
-  FormControl,
-  FormGroup,
-  UntypedFormControl,
-  UntypedFormGroup,
-} from '@angular/forms';
-import { createInvalidParam, createIssue } from '../../../test/error';
+import { AbstractControl, FormControl, FormGroup, UntypedFormControl, UntypedFormGroup } from '@angular/forms';
+import { faker } from '@faker-js/faker';
+import { createInvalidParam, createIssue, createProblemDetail } from '../../../test/error';
 import { InvalidParam, Issue } from '../tech.model';
-import {
-  getControlForInvalidParam,
-  getControlForIssue,
-  getMessageForInvalidParam,
-  getMessageForIssue,
-  setInvalidParamValidationError,
-  setIssueValidationError,
-} from './tech.validation.util';
+import { VALIDATION_MESSAGES, ValidationMessageCode } from './tech.validation.messages';
+import { getControlForInvalidParam, getControlForIssue, getFieldPath, getMessageForInvalidParam, getMessageForIssue, getMessageReason, setInvalidParamValidationError, setIssueValidationError } from './tech.validation.util';
 
 describe('ValidationUtils', () => {
   const baseField1Control: FormControl = new UntypedFormControl();
@@ -55,7 +44,7 @@ describe('ValidationUtils', () => {
   describe('set issue validation error', () => {
     describe('get control for issue', () => {
       it('should return base field control', () => {
-        const issue: Issue = { ...createIssue(), field: 'baseField1' };
+        const issue: Issue = { ...createIssue(), field: 'class.resource.baseField1' };
 
         const control: AbstractControl = getControlForIssue(form, issue);
 
@@ -63,24 +52,24 @@ describe('ValidationUtils', () => {
       });
 
       it('should return sub group field', () => {
-        const issue: Issue = { ...createIssue(), field: 'subGroup.subGroupField1' };
+        const issue: Issue = { ...createIssue(), field: 'class.resource.subGroup.subGroupField1' };
 
-        const control: AbstractControl = getControlForIssue(form, issue);
+        const control: AbstractControl = getControlForIssue(form, issue, 'resource');
 
         expect(control).toBe(subGroupFieldControl);
       });
 
       it('should ignore path prefix', () => {
-        const issue: Issue = { ...createIssue(), field: 'pathprefix.resource.baseField1' };
+        const issue: Issue = { ...createIssue(), field: 'class.resource.baseField1' };
 
-        const control: AbstractControl = getControlForIssue(form, issue, 'pathprefix.resource');
+        const control: AbstractControl = getControlForIssue(form, issue, 'resource');
 
         expect(control).toBe(baseField1Control);
       });
     });
 
     describe('in base field', () => {
-      const issue: Issue = { ...createIssue(), field: 'baseField1' };
+      const issue: Issue = { ...createIssue(), field: 'class.resource.baseField1' };
 
       it('should set error in control', () => {
         setIssueValidationError(form, issue);
@@ -108,10 +97,10 @@ describe('ValidationUtils', () => {
     });
 
     describe('in subGroup Field', () => {
-      const issue: Issue = { ...createIssue(), field: 'subGroup.subGroupField1' };
+      const issue: Issue = { ...createIssue(), field: 'class.resource.subGroup.subGroupField1' };
 
       it('should set error in control', () => {
-        setIssueValidationError(form, issue);
+        setIssueValidationError(form, issue, 'resource');
 
         expect(subGroupFieldControl.errors).not.toBeNull();
       });
@@ -150,102 +139,200 @@ describe('ValidationUtils', () => {
     });
   });
 
-  describe('invalid param', () => {
-    const formPrefixes: string[] = ['', 'some-prefix'];
-    const fieldNames: string[] = ['baseField1', 'baseField2', 'subGroup.subGroupField1'];
-    const prefixNameCombinations: string[][] = formPrefixes.flatMap((prefix) =>
-      fieldNames.map((name) => [prefix, name]),
-    );
-    const unknownName = 'unknown-field';
-
-    describe.each(prefixNameCombinations)(
-      'with prefix "%s" and fieldName "%s"',
-      (prefix, fieldName) => {
-        let invalidParam: InvalidParam;
-
-        beforeEach(() => {
-          form.reset();
-          invalidParam = {
-            ...createInvalidParam(),
-            name: prefix.length ? `${prefix}.${fieldName}` : fieldName,
-          };
-        });
-
-        describe('get message for invalid param', () => {
-          it('should return', () => {
-            const msg: string = getMessageForInvalidParam(invalidParam, prefix);
-
-            expect(msg).toEqual(`Bitte ${fieldName} ausfüllen`);
-          });
-        });
-
-        describe('get control for invalid param', () => {
-          it('should find', () => {
-            const control: AbstractControl = getControlForInvalidParam(form, invalidParam, prefix);
-
-            expect(control).toBeTruthy();
-          });
-        });
-
-        describe('set invalid param validation error', () => {
-          it('should assign invalidParam to form control error without prefix', () => {
-            const message: string = getMessageForInvalidParam(invalidParam, prefix);
-
-            setInvalidParamValidationError(form, invalidParam, prefix);
-
-            const errorMessage: string = form.getError(invalidParam.reason, fieldName);
-            expect(errorMessage).toBe(message);
-          });
-
-          it('should mark form as touched', () => {
-            setInvalidParamValidationError(form, invalidParam, prefix);
-
-            expect(form.touched).toBeTruthy();
-          });
-        });
-      },
-    );
-
-    describe.each([
-      ['', '', 'unknown-field'],
-      ['valid-prefix', 'valid-prefix', 'unknown-field'],
-      ['valid-prefix', 'valid-prefix', 'subGroup.unknown-field'],
-      ['unknown-prefix', 'valid-prefix', 'unknown-field'],
-      ['unknown-prefix', 'valid-prefix', 'baseField1'],
-    ])(
-      'with pathPrefix "%s", paramPrefix "%s", and field-name "%s"',
-      (pathPrefix, paramPrefix, fieldName) => {
-        let invalidParam: InvalidParam;
-
-        beforeEach(() => {
-          form.reset();
-          invalidParam = createInvalidParam();
-          invalidParam.name = paramPrefix.length > 0 ? `${paramPrefix}.${fieldName}` : fieldName;
-        });
-
-        it('should not find form control', () => {
-          const control: AbstractControl = getControlForInvalidParam(
-            form,
-            invalidParam,
-            pathPrefix,
-          );
-
-          expect(control).toBeFalsy();
-        });
-
-        it('should not assign to field control error', () => {
-          setInvalidParamValidationError(form, invalidParam, pathPrefix);
-
-          const errorMessage = form.getError(invalidParam.reason, unknownName);
-          expect(errorMessage).toBeFalsy();
-        });
-
-        it('should not mark as touched', () => {
-          setInvalidParamValidationError(form, invalidParam, pathPrefix);
-
-          expect(form.touched).toBeFalsy();
-        });
-      },
-    );
+  describe('set invalidParam validation error', () => {
+    describe('get control for invalidParam', () => {
+      it('should return base field control', () => {
+        const invalidParam: InvalidParam = {
+          ...createInvalidParam(),
+          name: 'class.resource.baseField1',
+        };
+
+        const control: AbstractControl = getControlForInvalidParam(form, invalidParam);
+
+        expect(control).toBe(baseField1Control);
+      });
+
+      it('should return sub group field', () => {
+        const invalidParam: InvalidParam = {
+          ...createInvalidParam(),
+          name: 'class.resource.subGroup.subGroupField1',
+        };
+
+        const control: AbstractControl = getControlForInvalidParam(form, invalidParam, 'resource');
+
+        expect(control).toBe(subGroupFieldControl);
+      });
+
+      it('should ignore path prefix', () => {
+        const invalidParam: InvalidParam = {
+          ...createInvalidParam(),
+          name: 'class.resource.baseField1',
+        };
+
+        const control: AbstractControl = getControlForInvalidParam(form, invalidParam, 'resource');
+
+        expect(control).toBe(baseField1Control);
+      });
+    });
+
+    describe('in base field', () => {
+      const invalidParam: InvalidParam = {
+        ...createInvalidParam(),
+        name: 'class.resource.baseField1',
+      };
+
+      it('should set error in control', () => {
+        setInvalidParamValidationError(form, invalidParam);
+
+        expect(baseField1Control.errors).not.toBeNull();
+      });
+
+      it('should set message code in control', () => {
+        setInvalidParamValidationError(form, invalidParam);
+
+        expect(baseField1Control.hasError(invalidParam.reason)).toBe(true);
+      });
+
+      it('should set control touched', () => {
+        setInvalidParamValidationError(form, invalidParam);
+
+        expect(baseField1Control.touched).toBe(true);
+      });
+
+      it('should not set error in other control', () => {
+        setInvalidParamValidationError(form, invalidParam);
+
+        expect(baseField2Control.errors).toBeNull();
+      });
+    });
+
+    describe('in subGroup Field', () => {
+      const invalidParam: InvalidParam = {
+        ...createInvalidParam(),
+        name: 'class.resource.subGroup.subGroupField1',
+      };
+
+      it('should set error in control', () => {
+        setInvalidParamValidationError(form, invalidParam, 'resource');
+
+        expect(subGroupFieldControl.errors).not.toBeNull();
+      });
+    });
+  });
+
+  describe('getFieldPath', () => {
+    const resource: string = 'resource';
+    const backendClassName: string = 'class';
+
+    it('should return field path', () => {
+      const fieldPath: string = 'field1';
+      const fullPath: string = `${backendClassName}.${resource}.${fieldPath}`;
+
+      const result: string = getFieldPath(fullPath, resource);
+
+      expect(result).toBe(fieldPath);
+    });
+
+    it('should get all parts after the prefix', () => {
+      const fieldPath: string = 'group.field1';
+      const fullPath: string = `${backendClassName}.${resource}.${fieldPath}`;
+
+      const result: string = getFieldPath(fullPath, resource);
+
+      expect(result).toBe(fieldPath);
+    });
+
+    it('should return field from full path when resource is undefined', () => {
+      const fieldPath: string = 'field1';
+      const fullPath: string = `${backendClassName}.${resource}.${fieldPath}`;
+
+      const result: string = getFieldPath(fullPath, undefined);
+
+      expect(result).toBe(fieldPath);
+    });
+
+    it('should return field from field when resource is undefined', () => {
+      const fieldPath: string = 'field1';
+
+      const result: string = getFieldPath(fieldPath, undefined);
+
+      expect(result).toBe(fieldPath);
+    });
+  });
+
+  describe('getMessageReason', () => {
+    it('should return reason', () => {
+      const problemDetail = createProblemDetail();
+
+      const reason: ValidationMessageCode = getMessageReason(problemDetail);
+
+      expect(reason).toEqual(problemDetail.invalidParams[0].reason);
+    });
+
+    it('should return null', () => {
+      const problemDetail = createProblemDetail([{ ...createInvalidParam(), reason: null }]);
+
+      const reason: ValidationMessageCode = getMessageReason(problemDetail);
+
+      expect(reason).toBeNull();
+    });
+  });
+
+  describe('getMessageForInvalidParam', () => {
+    const label: string = faker.random.word();
+
+    it('should return undefined reason', () => {
+      const invalidParam: InvalidParam = createInvalidParam();
+
+      const message: string = getMessageForInvalidParam(label, {
+        ...invalidParam,
+        reason: undefined,
+      });
+
+      expect(message).toBeUndefined();
+    });
+
+    it('should return message', () => {
+      const invalidParam: InvalidParam = createInvalidParam();
+
+      const message: string = getMessageForInvalidParam(label, {
+        ...invalidParam,
+        reason: ValidationMessageCode.FIELD_DATE_FORMAT_INVALID,
+      });
+      expect(message).toEqual(VALIDATION_MESSAGES[ValidationMessageCode.FIELD_DATE_FORMAT_INVALID]);
+    });
+
+    it('should return message with field placeholder', () => {
+      const invalidParam: InvalidParam = createInvalidParam();
+
+      const message: string = getMessageForInvalidParam(label, {
+        ...invalidParam,
+        reason: ValidationMessageCode.FIELD_INVALID,
+      });
+      expect(message).toEqual(
+        VALIDATION_MESSAGES[ValidationMessageCode.FIELD_INVALID].replace('{field}', label),
+      );
+    });
+
+    it('should return message with placeholders', () => {
+      const invalidParam: InvalidParam = createInvalidParam();
+      const min: string = '1';
+      const max: string = '5';
+
+      const message: string = getMessageForInvalidParam(label, {
+        ...invalidParam,
+        reason: ValidationMessageCode.FIELD_SIZE,
+        constraintParameters: [
+          { name: 'min', value: min },
+          { name: 'max', value: max },
+        ],
+      });
+      expect(message).toEqual(
+        VALIDATION_MESSAGES[ValidationMessageCode.FIELD_SIZE]
+          .replace('{field}', label)
+          .replace('{min}', min)
+          .replace('{max}', max),
+      );
+    });
   });
 });
diff --git a/alfa-client/libs/tech-shared/src/lib/validation/tech.validation.util.ts b/alfa-client/libs/tech-shared/src/lib/validation/tech.validation.util.ts
index 4a34005de2f231027678dc6ce606a8cc2e3e1bed..d562a4543baec28671348cd0ef81402c055b154d 100644
--- a/alfa-client/libs/tech-shared/src/lib/validation/tech.validation.util.ts
+++ b/alfa-client/libs/tech-shared/src/lib/validation/tech.validation.util.ts
@@ -22,9 +22,9 @@
  * unter der Lizenz sind dem Lizenztext zu entnehmen.
  */
 import { AbstractControl, UntypedFormGroup } from '@angular/forms';
-import { isNil } from 'lodash-es';
-import { ApiError, InvalidParam, Issue, IssueParam } from '../tech.model';
-import { isNotNil, replacePlaceholder } from '../tech.util';
+import { isEmpty, isNil } from 'lodash-es';
+import { ApiError, InvalidParam, Issue, IssueParam, ProblemDetail } from '../tech.model';
+import { replacePlaceholder } from '../tech.util';
 import { VALIDATION_MESSAGES, ValidationMessageCode } from './tech.validation.messages';
 
 export function isValidationError(issue: Issue): boolean {
@@ -47,7 +47,7 @@ export function getControlForIssue(
   issue: Issue,
   pathPrefix?: string,
 ): AbstractControl {
-  const fieldPath: string = getFieldPathWithoutPrefix(issue.field, pathPrefix);
+  const fieldPath: string = getFieldPath(issue.field, pathPrefix);
 
   let curControl: AbstractControl = form;
   fieldPath
@@ -72,8 +72,12 @@ export function getMessageForIssue(label: string, issue: Issue): string {
   return msg;
 }
 
-export function isValidationFieldFileSizeExceedError(error: any) {
-  return getMessageCode(error) === ValidationMessageCode.VALIDATION_FIELD_FILE_SIZE_EXCEEDED;
+export function isValidationFieldFileSizeExceedError(error: ProblemDetail): boolean {
+  return getMessageReason(error) === ValidationMessageCode.FIELD_FILE_SIZE_EXCEEDED;
+}
+
+export function getMessageReason(problemDetail: ProblemDetail): ValidationMessageCode | null {
+  return problemDetail.invalidParams[0].reason ?? null;
 }
 
 export function getMessageCode(apiError: ApiError): string {
@@ -86,12 +90,9 @@ export function setInvalidParamValidationError(
   pathPrefix?: string,
 ): void {
   const control: AbstractControl = getControlForInvalidParam(form, invalidParam, pathPrefix);
-  if (isNotNil(control)) {
-    control.setErrors({
-      [invalidParam.reason]: getMessageForInvalidParam(invalidParam, pathPrefix),
-    });
-    control.markAsTouched();
-  }
+
+  control.setErrors({ [invalidParam.reason]: invalidParam });
+  control.markAsTouched();
 }
 
 export function getControlForInvalidParam(
@@ -99,17 +100,29 @@ export function getControlForInvalidParam(
   invalidParam: InvalidParam,
   pathPrefix?: string,
 ): AbstractControl {
-  return form.get(getFieldPathWithoutPrefix(invalidParam.name, pathPrefix));
+  return form.get(getFieldPath(invalidParam.name, pathPrefix));
 }
 
-export function getMessageForInvalidParam(item: InvalidParam, pathPrefix: string): string {
-  return replacePlaceholder(
-    VALIDATION_MESSAGES[item.reason],
-    'field',
-    getFieldPathWithoutPrefix(item.name, pathPrefix),
+export function getMessageForInvalidParam(label: string, invalidParam: InvalidParam): string {
+  let msg: string = VALIDATION_MESSAGES[invalidParam.reason];
+
+  if (isNil(msg)) {
+    console.warn('No message for code ' + invalidParam.reason + ' found.');
+    return invalidParam.reason;
+  }
+
+  msg = replacePlaceholder(msg, 'field', label);
+  invalidParam.constraintParameters.forEach(
+    (param: IssueParam) => (msg = replacePlaceholder(msg, param.name, param.value)),
   );
+  return msg;
 }
 
-function getFieldPathWithoutPrefix(name: string, pathPrefix?: string): string {
-  return pathPrefix ? name.substring(pathPrefix.length + 1) : name;
+export function getFieldPath(name: string, pathPrefix: string): string {
+  if (isEmpty(pathPrefix)) {
+    return name.split('.').pop();
+  }
+
+  const indexOfField = name.lastIndexOf(pathPrefix) + pathPrefix.length + 1;
+  return name.slice(indexOfField);
 }
diff --git a/alfa-client/libs/tech-shared/test/error.ts b/alfa-client/libs/tech-shared/test/error.ts
index 9803a5a5ad90888ceb7125bc535f5c379548d126..3f80af06d43d07792780eaf023c378bcfd697345 100644
--- a/alfa-client/libs/tech-shared/test/error.ts
+++ b/alfa-client/libs/tech-shared/test/error.ts
@@ -23,7 +23,14 @@
  */
 import { HttpErrorResponse, HttpStatusCode } from '@angular/common/http';
 import { faker } from '@faker-js/faker';
-import { ApiError, InvalidParam, Issue, IssueParam, ProblemDetail } from '../src/lib/tech.model';
+import {
+  ApiError,
+  ConstraintParameter,
+  InvalidParam,
+  Issue,
+  IssueParam,
+  ProblemDetail,
+} from '../src/lib/tech.model';
 import { ValidationMessageCode } from '../src/lib/validation/tech.validation.messages';
 
 export function createIssueParam(): IssueParam {
@@ -63,10 +70,22 @@ export function createProblemDetail(
     type: faker.random.word(),
     instance: faker.internet.url(),
     detail: faker.random.word(),
-    'invalid-params': invalidParams,
+    invalidParams: invalidParams,
   };
 }
 
 export function createInvalidParam(): InvalidParam {
-  return { name: faker.random.word(), reason: ValidationMessageCode.VALIDATION_FIELD_EMPTY };
+  return {
+    name: faker.random.word(),
+    reason: ValidationMessageCode.FIELD_EMPTY,
+    value: faker.random.words(10),
+    constraintParameters: [createInvalidParamConstraintParameter()],
+  };
+}
+
+export function createInvalidParamConstraintParameter(): ConstraintParameter {
+  return {
+    name: faker.random.word(),
+    value: faker.random.word(),
+  };
 }
diff --git a/alfa-client/libs/ui/src/lib/assets/update.svg b/alfa-client/libs/ui/src/lib/assets/update.svg
index 1eb6a0751c7673b2de4a52c06aba58f191f32570..64c8cf90dc1a17b7183fd9dc03a66effd3273449 100644
--- a/alfa-client/libs/ui/src/lib/assets/update.svg
+++ b/alfa-client/libs/ui/src/lib/assets/update.svg
@@ -1 +1,4 @@
-<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#5f6368"><path d="M480-120q-75 0-140.5-28.5t-114-77q-48.5-48.5-77-114T120-480q0-75 28.5-140.5t77-114q48.5-48.5 114-77T480-840q82 0 155.5 35T760-706v-94h80v240H600v-80h110q-41-56-101-88t-129-32q-117 0-198.5 81.5T200-480q0 117 81.5 198.5T480-200q105 0 183.5-68T756-440h82q-15 137-117.5 228.5T480-120Zm112-192L440-464v-216h80v184l128 128-56 56Z"/></svg>
\ No newline at end of file
+<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="inherit">
+  <path
+    d="M480-120q-75 0-140.5-28.5t-114-77q-48.5-48.5-77-114T120-480q0-75 28.5-140.5t77-114q48.5-48.5 114-77T480-840q82 0 155.5 35T760-706v-94h80v240H600v-80h110q-41-56-101-88t-129-32q-117 0-198.5 81.5T200-480q0 117 81.5 198.5T480-200q105 0 183.5-68T756-440h82q-15 137-117.5 228.5T480-120Zm112-192L440-464v-216h80v184l128 128-56 56Z" />
+</svg>
\ No newline at end of file
diff --git a/alfa-client/libs/ui/src/lib/ui/editor/autocomplete-editor/autocomplete-editor.component.html b/alfa-client/libs/ui/src/lib/ui/editor/autocomplete-editor/autocomplete-editor.component.html
index 6f484f807eca85ab9ccc7bc42c43c12c9bdc850f..8a0fb969d94a66f00007edfff7f6f84f55edd969 100644
--- a/alfa-client/libs/ui/src/lib/ui/editor/autocomplete-editor/autocomplete-editor.component.html
+++ b/alfa-client/libs/ui/src/lib/ui/editor/autocomplete-editor/autocomplete-editor.component.html
@@ -54,7 +54,7 @@
   <mat-error>
     <ozgcloud-validation-error
       [attr.data-test-id]="(label | convertForDataTest) + '-autocomplete-error'"
-      [issues]="issues"
+      [invalidParams]="invalidParams"
       [label]="label"
     >
     </ozgcloud-validation-error>
diff --git a/alfa-client/libs/ui/src/lib/ui/editor/date-editor/date-editor.component.html b/alfa-client/libs/ui/src/lib/ui/editor/date-editor/date-editor.component.html
index 589e1679db0ad9e505aa9b98a1c981b366e5abfb..07ec3ad16554c885825d55b1f14139a7e05a246f 100644
--- a/alfa-client/libs/ui/src/lib/ui/editor/date-editor/date-editor.component.html
+++ b/alfa-client/libs/ui/src/lib/ui/editor/date-editor/date-editor.component.html
@@ -43,7 +43,7 @@
   <mat-error>
     <ozgcloud-validation-error
       [attr.data-test-id]="(label | convertForDataTest) + '-date-error'"
-      [issues]="issues"
+      [invalidParams]="invalidParams"
       [label]="label"
     ></ozgcloud-validation-error>
   </mat-error>
diff --git a/alfa-client/libs/ui/src/lib/ui/editor/file-upload-editor/file-upload-editor.component.html b/alfa-client/libs/ui/src/lib/ui/editor/file-upload-editor/file-upload-editor.component.html
index a6f83cf4e2fa94e8a84d5ee0aebbfd9fa1efd8d1..94acabf0cf558593f633a252fb6bdb35f07f5fd0 100644
--- a/alfa-client/libs/ui/src/lib/ui/editor/file-upload-editor/file-upload-editor.component.html
+++ b/alfa-client/libs/ui/src/lib/ui/editor/file-upload-editor/file-upload-editor.component.html
@@ -48,7 +48,7 @@
 <mat-error>
   <ozgcloud-validation-error
     [attr.data-test-id]="(label | convertForDataTest) + '-file-upload-error'"
-    [issues]="issues"
+    [invalidParams]="invalidParams"
     [label]="label"
   >
   </ozgcloud-validation-error>
diff --git a/alfa-client/libs/ui/src/lib/ui/editor/text-editor/text-editor.component.html b/alfa-client/libs/ui/src/lib/ui/editor/text-editor/text-editor.component.html
index bcf6e536c27a4a13aab0a99e43c2c155920bc241..8a8e01260fd7b5cb4af14320ea4af0d264b9a980 100644
--- a/alfa-client/libs/ui/src/lib/ui/editor/text-editor/text-editor.component.html
+++ b/alfa-client/libs/ui/src/lib/ui/editor/text-editor/text-editor.component.html
@@ -58,7 +58,7 @@
   <mat-error>
     <ozgcloud-validation-error
       [attr.data-test-id]="(getPlaceholderLabel() | convertForDataTest) + '-text-error'"
-      [issues]="issues"
+      [invalidParams]="invalidParams"
       [label]="getPlaceholderLabel()"
     ></ozgcloud-validation-error>
   </mat-error>
diff --git a/alfa-client/libs/ui/src/lib/ui/editor/textarea-editor/textarea-editor.component.html b/alfa-client/libs/ui/src/lib/ui/editor/textarea-editor/textarea-editor.component.html
index cf3135707e7a986230e2dc9957326bb1766a6a88..14034ce169db28951cd062e19343976a81ca8d7b 100644
--- a/alfa-client/libs/ui/src/lib/ui/editor/textarea-editor/textarea-editor.component.html
+++ b/alfa-client/libs/ui/src/lib/ui/editor/textarea-editor/textarea-editor.component.html
@@ -39,8 +39,8 @@
 
   <mat-error>
     <ozgcloud-validation-error
-      [issues]="issues"
       [label]="label"
+      [invalidParams]="invalidParams"
       [attr.data-test-id]="(label | convertForDataTest) + '-textarea-error'"
     >
     </ozgcloud-validation-error>
diff --git a/alfa-client/libs/ui/src/lib/ui/validation-error/validation-error.component.html b/alfa-client/libs/ui/src/lib/ui/validation-error/validation-error.component.html
index 13f1ef45c46566b76aad56247845108a014310e6..2c47c8ccdafa3929335cd41715394e7c2e11357d 100644
--- a/alfa-client/libs/ui/src/lib/ui/validation-error/validation-error.component.html
+++ b/alfa-client/libs/ui/src/lib/ui/validation-error/validation-error.component.html
@@ -23,4 +23,4 @@
     unter der Lizenz sind dem Lizenztext zu entnehmen.
 
 -->
-<span *ngFor="let issue of issues">{{ message(issue) }}</span>
+<span *ngFor="let invalidParam of invalidParams">{{ message(invalidParam) }}</span>
diff --git a/alfa-client/libs/ui/src/lib/ui/validation-error/validation-error.component.spec.ts b/alfa-client/libs/ui/src/lib/ui/validation-error/validation-error.component.spec.ts
index 299af463232908e4f3edec96f97f7fd912379b0e..e486895e359ed8cbb702456e19b5f88530683e48 100644
--- a/alfa-client/libs/ui/src/lib/ui/validation-error/validation-error.component.spec.ts
+++ b/alfa-client/libs/ui/src/lib/ui/validation-error/validation-error.component.spec.ts
@@ -21,8 +21,10 @@
  * Die sprachspezifischen Genehmigungen und Beschränkungen
  * unter der Lizenz sind dem Lizenztext zu entnehmen.
  */
+import { InvalidParam, getMessageForInvalidParam } from '@alfa-client/tech-shared';
 import { ComponentFixture, TestBed } from '@angular/core/testing';
-import { createIssue } from 'libs/tech-shared/test/error';
+import { ValidationMessageCode } from 'libs/tech-shared/src/lib/validation/tech.validation.messages';
+import { createInvalidParam } from 'libs/tech-shared/test/error';
 import { ValidationErrorComponent } from './validation-error.component';
 
 describe('ValidationErrorComponent', () => {
@@ -45,9 +47,32 @@ describe('ValidationErrorComponent', () => {
     expect(component).toBeTruthy();
   });
 
-  it('should get message', () => {
-    var msg = component.message({ ...createIssue(), messageCode: 'validation_field_size' });
+  describe('get message from invalidParam', () => {
+    const fieldLabel: string = 'Field Label';
+    const invalidParam: InvalidParam = {
+      ...createInvalidParam(),
+      reason: ValidationMessageCode.FIELD_SIZE,
+    };
 
-    expect(msg).not.toHaveLength(0);
+    it('should contain ', () => {
+      const msg: string = getMessageForInvalidParam(fieldLabel, invalidParam);
+
+      expect(msg).toContain('muss mindestens');
+    });
+
+    it('should set field label', () => {
+      const msg: string = getMessageForInvalidParam(fieldLabel, invalidParam);
+
+      expect(msg).toContain(fieldLabel);
+    });
+
+    it('should replace min param', () => {
+      const msg: string = getMessageForInvalidParam(fieldLabel, {
+        ...invalidParam,
+        constraintParameters: [{ name: 'min', value: '3' }],
+      });
+
+      expect(msg).toContain('3');
+    });
   });
 });
diff --git a/alfa-client/libs/ui/src/lib/ui/validation-error/validation-error.component.ts b/alfa-client/libs/ui/src/lib/ui/validation-error/validation-error.component.ts
index 0432ac003dae9960503559194148fb5d79f52c45..1c5e6df544c2a3d480dd40d6915b72ef166c7273 100644
--- a/alfa-client/libs/ui/src/lib/ui/validation-error/validation-error.component.ts
+++ b/alfa-client/libs/ui/src/lib/ui/validation-error/validation-error.component.ts
@@ -21,8 +21,8 @@
  * Die sprachspezifischen Genehmigungen und Beschränkungen
  * unter der Lizenz sind dem Lizenztext zu entnehmen.
  */
+import { InvalidParam, getMessageForInvalidParam } from '@alfa-client/tech-shared';
 import { Component, Input } from '@angular/core';
-import { getMessageForIssue, Issue } from '@alfa-client/tech-shared';
 
 @Component({
   selector: 'ozgcloud-validation-error',
@@ -31,9 +31,9 @@ import { getMessageForIssue, Issue } from '@alfa-client/tech-shared';
 })
 export class ValidationErrorComponent {
   @Input() label: string;
-  @Input() issues: Issue[];
+  @Input() invalidParams: InvalidParam[];
 
-  public message(issue: Issue): string {
-    return getMessageForIssue(this.label, issue);
+  public message(invalidParam: InvalidParam): string {
+    return getMessageForInvalidParam(this.label, invalidParam);
   }
 }
diff --git a/alfa-client/libs/user-assistance/src/lib/help-menu/help-menu.component.html b/alfa-client/libs/user-assistance/src/lib/help-menu/help-menu.component.html
index 2b0db504b3f464f1624afcbceb95df15cfb6e3e0..8c00cbfc6abd899bf3da59fc774efc61a8c19755 100644
--- a/alfa-client/libs/user-assistance/src/lib/help-menu/help-menu.component.html
+++ b/alfa-client/libs/user-assistance/src/lib/help-menu/help-menu.component.html
@@ -5,9 +5,9 @@
   [matMenuTriggerFor]="helpMenu.matMenu"
   data-test-id="help-menu-button"
 >
-  <div class="help-menu">
-    <ozgcloud-icon icon="help_outline"></ozgcloud-icon>
-    <div class="text">Hilfe</div>
+  <div class="flex items-center text-ozggray-800 dark:text-ozggray-300">
+    <ozgcloud-icon class="mr-1" icon="help_outline"></ozgcloud-icon>
+    <div>Hilfe</div>
   </div>
 </button>
 <ozgcloud-menu #helpMenu>
diff --git a/alfa-client/libs/user-assistance/src/lib/help-menu/help-menu.component.scss b/alfa-client/libs/user-assistance/src/lib/help-menu/help-menu.component.scss
deleted file mode 100644
index 99cbeef04c23dba9c76fa256dbdb4764f5a1e2b4..0000000000000000000000000000000000000000
--- a/alfa-client/libs/user-assistance/src/lib/help-menu/help-menu.component.scss
+++ /dev/null
@@ -1,11 +0,0 @@
-@import 'variables';
-
-.help-menu {
-  display: flex;
-  align-items: center;
-  color: $grey;
-}
-
-ozgcloud-icon {
-  margin-right: 4px;
-}
diff --git a/alfa-client/libs/user-assistance/src/lib/help-menu/help-menu.component.ts b/alfa-client/libs/user-assistance/src/lib/help-menu/help-menu.component.ts
index 602c0ee4effc7366a69024c531427d7ff5410ae9..5c7c59840a98bac1696c1a1b3a5b5de3c9b14618 100644
--- a/alfa-client/libs/user-assistance/src/lib/help-menu/help-menu.component.ts
+++ b/alfa-client/libs/user-assistance/src/lib/help-menu/help-menu.component.ts
@@ -1,12 +1,11 @@
-import { Component, Input } from '@angular/core';
 import { ApiRootLinkRel, ApiRootResource } from '@alfa-client/api-root-shared';
 import { StateResource } from '@alfa-client/tech-shared';
+import { Component, Input } from '@angular/core';
 import { hasLink } from '@ngxp/rest';
 
 @Component({
   selector: 'alfa-help-menu',
   templateUrl: './help-menu.component.html',
-  styleUrls: ['./help-menu.component.scss'],
 })
 export class HelpMenuComponent {
   @Input() apiRootStateResource: StateResource<ApiRootResource>;
diff --git a/alfa-client/libs/user-profile/src/lib/user-profile-search-container/user-profile-search/user-profile.search.formservice.ts b/alfa-client/libs/user-profile/src/lib/user-profile-search-container/user-profile-search/user-profile.search.formservice.ts
index 4ec86ff50492e343fb1fe25fe2936d8cab1e8e9a..7293348a84e515fc1ae97109279f3ea8e49375d4 100644
--- a/alfa-client/libs/user-profile/src/lib/user-profile-search-container/user-profile-search/user-profile.search.formservice.ts
+++ b/alfa-client/libs/user-profile/src/lib/user-profile-search-container/user-profile-search/user-profile.search.formservice.ts
@@ -21,12 +21,13 @@
  * Die sprachspezifischen Genehmigungen und Beschränkungen
  * unter der Lizenz sind dem Lizenztext zu entnehmen.
  */
+import { AbstractFormService, ProblemDetail, StateResource } from '@alfa-client/tech-shared';
+import { UserProfileListResource, UserProfileService } from '@alfa-client/user-profile-shared';
 import { Injectable, OnDestroy } from '@angular/core';
 import { UntypedFormBuilder, UntypedFormControl, UntypedFormGroup } from '@angular/forms';
-import { AbstractFormService, StateResource } from '@alfa-client/tech-shared';
-import { UserProfileListResource, UserProfileService } from '@alfa-client/user-profile-shared';
 import { isNil } from 'lodash-es';
 import { Observable, Subscription } from 'rxjs';
+import { ValidationMessageCode } from '../../../../../tech-shared/src/lib/validation/tech.validation.messages';
 
 @Injectable()
 export class UserProfileSearchFormService extends AbstractFormService implements OnDestroy {
@@ -62,11 +63,11 @@ export class UserProfileSearchFormService extends AbstractFormService implements
   }
 
   public setEmptyUserProfileError(): void {
-    this.setErrorByApiError(emptyUserProfileError);
+    this.setErrorByProblemDetail(emptyUserProfileError);
   }
 
   public setNoUserProfileFoundError(): void {
-    this.setErrorByApiError(noUserProfileFoundError);
+    this.setErrorByProblemDetail(noUserProfileFoundError);
   }
 
   ngOnDestroy(): void {
@@ -74,23 +75,34 @@ export class UserProfileSearchFormService extends AbstractFormService implements
   }
 }
 
-const noUserProfileFoundError = {
-  issues: [
+const noUserProfileFoundError: ProblemDetail = {
+  type: null,
+  title: null,
+  status: null,
+  detail: null,
+  instance: null,
+  invalidParams: [
     {
-      field: 'only.fe.searchBy',
-      message: 'fe_only_validation_bearbeiter_not_exist',
-      messageCode: 'fe_only_validation_bearbeiter_not_exist',
-      parameters: [],
+      name: 'only.fe.searchBy',
+      reason: ValidationMessageCode.FIELD_ASSIGN_BEARBEITER_NOT_EXIST,
+      constraintParameters: [],
+      value: null,
     },
   ],
 };
-const emptyUserProfileError = {
-  issues: [
+
+const emptyUserProfileError: ProblemDetail = {
+  type: null,
+  title: null,
+  status: null,
+  detail: null,
+  instance: null,
+  invalidParams: [
     {
-      field: 'only.fe.searchBy',
-      message: 'validation_field_empty',
-      messageCode: 'validation_field_empty',
-      parameters: [],
+      name: 'only.fe.searchBy',
+      reason: ValidationMessageCode.FIELD_EMPTY,
+      constraintParameters: [],
+      value: null,
     },
   ],
 };
diff --git a/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-bescheiden/vorgang-detail-bescheiden-result/vorgang-detail-bescheiden-result-attachments/vorgang-detail-bescheiden-result-attachments.component.html b/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-bescheiden/vorgang-detail-bescheiden-result/vorgang-detail-bescheiden-result-attachments/vorgang-detail-bescheiden-result-attachments.component.html
index ff4e542e0d9181e9ee7bc98b468e62b2a1d23482..78e9fba0ee241ee0b39e7a9e4d771e48cb1b84fd 100644
--- a/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-bescheiden/vorgang-detail-bescheiden-result/vorgang-detail-bescheiden-result-attachments/vorgang-detail-bescheiden-result-attachments.component.html
+++ b/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-bescheiden/vorgang-detail-bescheiden-result/vorgang-detail-bescheiden-result-attachments/vorgang-detail-bescheiden-result-attachments.component.html
@@ -22,7 +22,7 @@
       *ngIf="uploadFileInProgress.loading || uploadFileInProgress.error"
       [loadingCaption]="uploadFileInProgress.fileName"
       errorCaption="Fehler beim Hochladen"
-      [errorMessages]="uploadFileInProgress.error | convertApiErrorToErrorMessages"
+      [errorMessages]="uploadFileInProgress.error | convertProblemDetailToErrorMessages"
       description="Anhang wird hochgeladen"
       [isLoading]="uploadFileInProgress.loading"
     ></ods-attachment>
diff --git a/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-bescheiden/vorgang-detail-bescheiden-result/vorgang-detail-bescheiden-result-attachments/vorgang-detail-bescheiden-result-attachments.component.spec.ts b/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-bescheiden/vorgang-detail-bescheiden-result/vorgang-detail-bescheiden-result-attachments/vorgang-detail-bescheiden-result-attachments.component.spec.ts
index 63758c537759f45fbe750b6c286b6b2e5778864d..caed9958a4f9dc70ae170976ae44c01c77e8e235 100644
--- a/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-bescheiden/vorgang-detail-bescheiden-result/vorgang-detail-bescheiden-result-attachments/vorgang-detail-bescheiden-result-attachments.component.spec.ts
+++ b/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-bescheiden/vorgang-detail-bescheiden-result/vorgang-detail-bescheiden-result-attachments/vorgang-detail-bescheiden-result-attachments.component.spec.ts
@@ -2,7 +2,6 @@ import { BescheidService } from '@alfa-client/bescheid-shared';
 import { BinaryFile2ContainerComponent } from '@alfa-client/binary-file';
 import { BinaryFileResource } from '@alfa-client/binary-file-shared';
 import {
-  ConvertApiErrorToErrorMessagesPipe,
   convertForDataTest,
   ConvertForDataTestPipe,
   createErrorStateResource,
@@ -15,6 +14,7 @@ import { OzgcloudSvgIconComponent, SpinnerComponent } from '@alfa-client/ui';
 import { ComponentFixture, TestBed } from '@angular/core/testing';
 import { MatIcon } from '@angular/material/icon';
 import { AttachmentComponent, AttachmentWrapperComponent, SpinnerIconComponent } from '@ods/system';
+import { ConvertProblemDetailToErrorMessagesPipe } from 'libs/tech-shared/src/lib/pipe/convert-problem-detail-to-error-messages.pipe';
 import { MockComponent, MockPipe } from 'ng-mocks';
 import { BehaviorSubject, EMPTY, Observable, of, Subscription } from 'rxjs';
 import { createUploadFileInProgress } from '../../../../../../../bescheid-shared/src/test/bescheid';
@@ -51,7 +51,7 @@ describe('VorgangDetailBescheidenResultAttachmentsComponent', () => {
         ConvertForDataTestPipe,
         MatIcon,
         MockPipe(FileSizePipe),
-        MockPipe(ConvertApiErrorToErrorMessagesPipe),
+        MockPipe(ConvertProblemDetailToErrorMessagesPipe),
         MockComponent(OzgcloudSvgIconComponent),
         MockComponent(SpinnerComponent),
         MockComponent(AttachmentWrapperComponent),
diff --git a/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-bescheiden/vorgang-detail-bescheiden-result/vorgang-detail-bescheiden-result-dokument/vorgang-detail-bescheiden-result-dokument.component.html b/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-bescheiden/vorgang-detail-bescheiden-result/vorgang-detail-bescheiden-result-dokument/vorgang-detail-bescheiden-result-dokument.component.html
index bb762af88d7b449d222804be6eccd2be60690f5e..d94edab530d6fb8fcdce754bee1d5083f0e7e6b7 100644
--- a/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-bescheiden/vorgang-detail-bescheiden-result/vorgang-detail-bescheiden-result-dokument/vorgang-detail-bescheiden-result-dokument.component.html
+++ b/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-bescheiden/vorgang-detail-bescheiden-result/vorgang-detail-bescheiden-result-dokument/vorgang-detail-bescheiden-result-dokument.component.html
@@ -27,7 +27,7 @@
       'upload-bescheid-document-error-' + !!uploadBescheidDocumentInProgress.error
     "
     [isLoading]="uploadBescheidDocumentInProgress.loading"
-    [errorMessages]="uploadBescheidDocumentInProgress.error | convertApiErrorToErrorMessages"
+    [errorMessages]="uploadBescheidDocumentInProgress.error | convertProblemDetailToErrorMessages"
     description="Bescheiddokument wird hochgeladen"
   ></ods-attachment>
   <ods-attachment
diff --git a/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-bescheiden/vorgang-detail-bescheiden-result/vorgang-detail-bescheiden-result-dokument/vorgang-detail-bescheiden-result-dokument.component.spec.ts b/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-bescheiden/vorgang-detail-bescheiden-result/vorgang-detail-bescheiden-result-dokument/vorgang-detail-bescheiden-result-dokument.component.spec.ts
index c61b90e368bb525ef644dfd2e95d156c06338d22..7dceb5ce5ba5e75c88ddb80fdd529a89b3e5ed41 100644
--- a/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-bescheiden/vorgang-detail-bescheiden-result/vorgang-detail-bescheiden-result-dokument/vorgang-detail-bescheiden-result-dokument.component.spec.ts
+++ b/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-bescheiden/vorgang-detail-bescheiden-result/vorgang-detail-bescheiden-result-dokument/vorgang-detail-bescheiden-result-dokument.component.spec.ts
@@ -2,7 +2,6 @@ import { BescheidLinkRel, BescheidResource, BescheidService } from '@alfa-client
 import { BinaryFile2ContainerComponent } from '@alfa-client/binary-file';
 import { CommandResource } from '@alfa-client/command-shared';
 import {
-  ConvertApiErrorToErrorMessagesPipe,
   StateResource,
   createEmptyStateResource,
   createStateResource,
@@ -13,6 +12,7 @@ import { getUrl } from '@ngxp/rest';
 import { AttachmentComponent, AttachmentWrapperComponent } from '@ods/system';
 import { createBescheidResource } from 'libs/bescheid-shared/src/test/bescheid';
 import { createBinaryFileResource } from 'libs/binary-file-shared/test/binary-file';
+import { ConvertProblemDetailToErrorMessagesPipe } from 'libs/tech-shared/src/lib/pipe/convert-problem-detail-to-error-messages.pipe';
 import { getDataTestIdOf } from 'libs/tech-shared/test/data-test';
 import { createApiError } from 'libs/tech-shared/test/error';
 import { MockComponent, MockPipe } from 'ng-mocks';
@@ -48,7 +48,7 @@ describe('VorgangDetailBescheidenResultDokumentComponent', () => {
         MockComponent(BinaryFile2ContainerComponent),
         MockComponent(AttachmentComponent),
         MockComponent(AttachmentWrapperComponent),
-        MockPipe(ConvertApiErrorToErrorMessagesPipe),
+        MockPipe(ConvertProblemDetailToErrorMessagesPipe),
       ],
       providers: [
         {
diff --git a/alfa-client/libs/vorgang-shared-ui/src/lib/wiedervorlage-icon/wiedervorlage-icon.component.html b/alfa-client/libs/vorgang-shared-ui/src/lib/wiedervorlage-icon/wiedervorlage-icon.component.html
index 9bf2265a277651fe8d40eff1a80ad736136077ea..929a086df43bd18a6e9a4b0097d02c877d3d51e1 100644
--- a/alfa-client/libs/vorgang-shared-ui/src/lib/wiedervorlage-icon/wiedervorlage-icon.component.html
+++ b/alfa-client/libs/vorgang-shared-ui/src/lib/wiedervorlage-icon/wiedervorlage-icon.component.html
@@ -1,4 +1,7 @@
-<div [class.red]="isOverdue" data-test-class="wiedervorlage-icon">
+<div
+  [ngClass]="{ 'text-error': isOverdue, 'text-text': !isOverdue }"
+  data-test-class="wiedervorlage-icon"
+>
   <ng-container *ngIf="isOverdue; else defaultFrist">
     <ozgcloud-svgicon
       svgIcon="resubmission_expired"
diff --git a/alfa-client/libs/vorgang-shared-ui/src/lib/wiedervorlage-icon/wiedervorlage-icon.component.scss b/alfa-client/libs/vorgang-shared-ui/src/lib/wiedervorlage-icon/wiedervorlage-icon.component.scss
index 9315d4d7758a4c1fcfe23122a58d1d7059d8b257..5d71aeb617f12da1e3cf893fb102314114d1e7df 100644
--- a/alfa-client/libs/vorgang-shared-ui/src/lib/wiedervorlage-icon/wiedervorlage-icon.component.scss
+++ b/alfa-client/libs/vorgang-shared-ui/src/lib/wiedervorlage-icon/wiedervorlage-icon.component.scss
@@ -6,11 +6,3 @@
   margin-right: 6px;
   height: $iconHeight;
 }
-
-.red {
-  color: mat.get-color-from-palette($warnPalette, darker);
-}
-
-body.dark :host .red {
-  color: red;
-}
diff --git a/alfa-client/libs/vorgang/src/lib/vorgang-list-container/vorgang-list/vorgang-list-item/vorgang-next-frist-button/vorgang-next-frist-button.component.html b/alfa-client/libs/vorgang/src/lib/vorgang-list-container/vorgang-list/vorgang-list-item/vorgang-next-frist-button/vorgang-next-frist-button.component.html
index 37b136c5f1d31d7d6f21f87df330bec6cce80a9c..206b3aa1c4c6986f0b4f18fdcb876810bf81d610 100644
--- a/alfa-client/libs/vorgang/src/lib/vorgang-list-container/vorgang-list/vorgang-list-item/vorgang-next-frist-button/vorgang-next-frist-button.component.html
+++ b/alfa-client/libs/vorgang/src/lib/vorgang-list-container/vorgang-list/vorgang-list-item/vorgang-next-frist-button/vorgang-next-frist-button.component.html
@@ -31,7 +31,11 @@
   (mouseleave)="showWiedervorlagen = false"
   (focusout)="showWiedervorlagen = false"
 >
-  <div class="date" [class.red]="isOverdue" data-test-class="wiedervorlage-next-frist">
+  <div
+    class="date"
+    [ngClass]="{ 'text-error': isOverdue, 'text-text': !isOverdue }"
+    data-test-class="wiedervorlage-next-frist"
+  >
     <alfa-wiedervorlage-icon [isOverdue]="isOverdue"></alfa-wiedervorlage-icon>
     <span>{{ vorgang.nextFrist | formatToPrettyDate }}</span>
   </div>
diff --git a/alfa-client/libs/vorgang/src/lib/vorgang-list-container/vorgang-list/vorgang-list-item/vorgang-next-frist-button/vorgang-next-frist-button.component.scss b/alfa-client/libs/vorgang/src/lib/vorgang-list-container/vorgang-list/vorgang-list-item/vorgang-next-frist-button/vorgang-next-frist-button.component.scss
index aa806fcb134fd31ffe3294c79892fccf159157fa..458f0a6eb3a1c8807675fab809d27e13ca79503b 100644
--- a/alfa-client/libs/vorgang/src/lib/vorgang-list-container/vorgang-list/vorgang-list-item/vorgang-next-frist-button/vorgang-next-frist-button.component.scss
+++ b/alfa-client/libs/vorgang/src/lib/vorgang-list-container/vorgang-list/vorgang-list-item/vorgang-next-frist-button/vorgang-next-frist-button.component.scss
@@ -29,7 +29,6 @@
   background-color: inherit;
   border: 0;
   padding: 0;
-  color: inherit;
   position: relative;
 }
 
@@ -38,11 +37,3 @@
   align-items: center;
   white-space: nowrap;
 }
-
-.red {
-  color: mat.get-color-from-palette($warnPalette, darker);
-}
-
-body.dark :host .red {
-  color: red;
-}
diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/common/errorhandling/ExceptionController.java b/alfa-service/src/main/java/de/ozgcloud/alfa/common/errorhandling/ExceptionController.java
index 5e4f5be4e7d0a8077ab670e49769d3655c8abd47..facaacd37af7212818e9e220331f7c6a24c4c4a4 100644
--- a/alfa-service/src/main/java/de/ozgcloud/alfa/common/errorhandling/ExceptionController.java
+++ b/alfa-service/src/main/java/de/ozgcloud/alfa/common/errorhandling/ExceptionController.java
@@ -23,49 +23,38 @@
  */
 package de.ozgcloud.alfa.common.errorhandling;
 
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map.Entry;
-import java.util.Objects;
-import java.util.Optional;
-import java.util.Set;
 import java.util.UUID;
-import java.util.stream.Stream;
 
-import jakarta.validation.ConstraintViolation;
 import jakarta.validation.ConstraintViolationException;
-import jakarta.validation.Path;
-import jakarta.validation.metadata.ConstraintDescriptor;
 
-import org.hibernate.validator.engine.HibernateConstraintViolation;
 import org.springframework.core.annotation.Order;
 import org.springframework.http.HttpStatus;
+import org.springframework.http.ProblemDetail;
 import org.springframework.security.access.AccessDeniedException;
-import org.springframework.web.bind.annotation.ControllerAdvice;
 import org.springframework.web.bind.annotation.ExceptionHandler;
-import org.springframework.web.bind.annotation.ResponseBody;
 import org.springframework.web.bind.annotation.ResponseStatus;
+import org.springframework.web.bind.annotation.RestControllerAdvice;
+import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;
 
-import de.ozgcloud.alfa.common.binaryfile.DynamicViolationParameter;
 import de.ozgcloud.common.errorhandling.ExceptionUtil;
 import de.ozgcloud.common.errorhandling.TechnicalException;
+import lombok.RequiredArgsConstructor;
 import lombok.extern.log4j.Log4j2;
 
-@ControllerAdvice
+@RestControllerAdvice
+@RequiredArgsConstructor
 @Log4j2
 @Order(98)
-public class ExceptionController {
-
-	private static final Set<String> IGNORABLE_CONSTRAINT_VIOLATION_ATTRIBUTES = new HashSet<>(Arrays.asList("groups", "payload", "message"));
+public class ExceptionController extends ResponseEntityExceptionHandler {
 
 	static final String RUNTIME_MESSAGE_CODE = "generale.server_error";
 	static final String RESOURCE_NOT_FOUNT_MESSAGE_CODE = "resource.not_found";
 	static final String ACCESS_DENIED_MESSAGE_CODE = "generale.access_denied";
 
+	private final ProblemDetailMapper problemDetailMapper;
+
 	@ExceptionHandler(FunctionalException.class)
 	@ResponseStatus(HttpStatus.BAD_REQUEST)
-	@ResponseBody
 	public ApiError handleFunctionalException(FunctionalException e) {
 		LOG.error("BadRequest", e);
 		return ApiError.builder().issue(buildIssueForFunctionalException(e)).build();
@@ -77,7 +66,6 @@ public class ExceptionController {
 
 	@ExceptionHandler(AccessDeniedException.class)
 	@ResponseStatus(HttpStatus.FORBIDDEN)
-	@ResponseBody
 	public ApiError handleAccessDeniedException(AccessDeniedException e) {
 		var exceptionId = createExceptionId();
 		var messageWithExceptionId = ExceptionUtil.formatMessageWithExceptionId(e.getMessage(), exceptionId);
@@ -92,7 +80,6 @@ public class ExceptionController {
 
 	@ExceptionHandler(ResourceNotFoundException.class)
 	@ResponseStatus(HttpStatus.NOT_FOUND)
-	@ResponseBody
 	public ApiError handleResourceNotFoundException(ResourceNotFoundException e) {
 		LOG.warn("Resource not found: {}", e.getMessage());
 		return ApiError.builder().issue(buildIssueForResourceNotFoundException(e)).build();
@@ -103,66 +90,14 @@ public class ExceptionController {
 	}
 
 	@ExceptionHandler(ConstraintViolationException.class)
-	@ResponseStatus(HttpStatus.UNPROCESSABLE_ENTITY)
-	@ResponseBody
-	public ApiError handleConstraintViolationException(ConstraintViolationException e) {
-		var exceptionId = createExceptionId();
-		var messageWithExceptionId = ExceptionUtil.formatMessageWithExceptionId(e.getMessage(), exceptionId);
-		LOG.warn("Validation Exception: {}", messageWithExceptionId);
-		return ApiError.builder().issues(buildIssues(e, exceptionId)).build();
-	}
-
-	private List<Issue> buildIssues(ConstraintViolationException e, String exceptionId) {
-		return e.getConstraintViolations().stream()
-				.map(violation -> buildIssue(violation, exceptionId))
-				.toList();
-	}
-
-	private Issue buildIssue(ConstraintViolation<?> violation, String exceptionId) {
-		return Issue.builder()//
-				.field(buildFieldPath(violation.getPropertyPath()))//
-				.messageCode(violation.getMessageTemplate().replace("{", "").replace("}", ""))//
-				.message(violation.getMessage())//
-				.parameters(buildParameters(violation).toList())
-				.exceptionId(exceptionId)
-				.build();
-	}
-
-	private String buildFieldPath(Path propertyPath) {
-		return propertyPath.toString().substring(propertyPath.toString().indexOf('.') + 1);
-	}
-
-	Stream<IssueParam> buildParameters(ConstraintViolation<?> violation) {
-		var dynamicPayload = getDynamicPayload(violation);
-		return Optional.ofNullable(violation.getConstraintDescriptor())
-				.map(ConstraintDescriptor::getAttributes)
-				.map(descr -> descr.entrySet().stream()
-						.filter(entry -> !IGNORABLE_CONSTRAINT_VIOLATION_ATTRIBUTES.contains(entry.getKey()))
-						.map(entryMap -> buildIssueParam(entryMap, dynamicPayload)))
-				.orElse(Stream.empty());
-	}
-
-	private IssueParam buildIssueParam(Entry<String, Object> entry, Optional<DynamicViolationParameter> dynamicValues) {
-		return IssueParam.builder().name(entry.getKey()).value(getValue(entry, dynamicValues)).build();
-	}
-
-	private String getValue(Entry<String, Object> entry, Optional<DynamicViolationParameter> dynamicValues) {
-		return dynamicValues
-				.map(DynamicViolationParameter::getMap)
-				.map(map -> map.get(entry.getKey()))
-				.filter(Objects::nonNull)
-				.map(String::valueOf)
-				.orElse(String.valueOf(entry.getValue()));
-	}
+	public ProblemDetail handleConstraintViolationException(ConstraintViolationException e) {
+		LOG.warn("Validation Exception: {}", problemDetailMapper.buildMessageWithExceptionId(e));
 
-	private Optional<DynamicViolationParameter> getDynamicPayload(ConstraintViolation<?> violation) {
-		HibernateConstraintViolation<?> hibernateViolation = violation.unwrap(HibernateConstraintViolation.class);
-		return Optional.ofNullable(hibernateViolation.getDynamicPayload(DynamicViolationParameter.class));
+		return problemDetailMapper.fromConstraintViolationException(e);
 	}
 
 	@ExceptionHandler(TechnicalException.class)
 	@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
-	@ResponseBody
 	public ApiError handleTechnicalException(TechnicalException e) {
 		LOG.error("TechnicalException on Request", e);
 		return buildRuntimeApiError(e.getMessage(), e.getExceptionId());
@@ -170,7 +105,6 @@ public class ExceptionController {
 
 	@ExceptionHandler(RuntimeException.class)
 	@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
-	@ResponseBody
 	public ApiError handleRuntimeException(RuntimeException e) {
 		var exceptionId = createExceptionId();
 		var messageWithExceptionId = ExceptionUtil.formatMessageWithExceptionId(e.getMessage(), exceptionId);
diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/common/errorhandling/ProblemDetailMapper.java b/alfa-service/src/main/java/de/ozgcloud/alfa/common/errorhandling/ProblemDetailMapper.java
new file mode 100644
index 0000000000000000000000000000000000000000..c4a358f396674e8bcd4f8f4fb36eb677eec7b74b
--- /dev/null
+++ b/alfa-service/src/main/java/de/ozgcloud/alfa/common/errorhandling/ProblemDetailMapper.java
@@ -0,0 +1,90 @@
+package de.ozgcloud.alfa.common.errorhandling;
+
+import java.util.Collections;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.Set;
+import java.util.UUID;
+import java.util.stream.Stream;
+
+import jakarta.validation.ConstraintViolation;
+import jakarta.validation.ConstraintViolationException;
+import jakarta.validation.metadata.ConstraintDescriptor;
+
+import org.hibernate.validator.engine.HibernateConstraintViolation;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ProblemDetail;
+import org.springframework.stereotype.Component;
+
+import de.ozgcloud.alfa.common.binaryfile.DynamicViolationParameter;
+import de.ozgcloud.common.errorhandling.ExceptionUtil;
+
+@Component
+public class ProblemDetailMapper {
+
+	static final String INVALID_PARAMS_KEY_CONSTRAINT_PARAMETERS = "constraintParameters";
+	static final String INVALID_PARAMS_KEY_REASON = "reason";
+	static final String INVALID_PARAMS_KEY_VALUE = "value";
+	static final String INVALID_PARAMS_KEY_NAME = "name";
+	static final String INVALID_PARAMS = "invalidParams";
+	static final String PROVIDED_VALUE_WAS_NULL = "Provided value was null!";
+	private static final Set<String> IGNORABLE_CONSTRAINT_VIOLATION_ATTRIBUTES = Set.of("groups", "payload", "message");
+
+	public ProblemDetail fromConstraintViolationException(ConstraintViolationException e) {
+		var problemDetail = ProblemDetail.forStatusAndDetail(HttpStatus.UNPROCESSABLE_ENTITY, buildMessageWithExceptionId(e));
+		problemDetail.setProperty(INVALID_PARAMS, buildInvalidParams(e.getConstraintViolations()).toList());
+		return problemDetail;
+	}
+
+	public String buildMessageWithExceptionId(ConstraintViolationException e) {
+		var exceptionId = createExceptionId();
+		return ExceptionUtil.formatMessageWithExceptionId(e.getLocalizedMessage(),
+				exceptionId);
+	}
+
+	String createExceptionId() {
+		return UUID.randomUUID().toString();
+	}
+
+	Stream<Map<String, Object>> buildInvalidParams(Set<ConstraintViolation<?>> violations) {
+		return Objects.requireNonNullElse(violations, Collections.<ConstraintViolation<?>>emptySet()).stream().map(this::buildDetailedViolation);
+	}
+
+	Map<String, Object> buildDetailedViolation(ConstraintViolation<?> violation) {
+		return Map.of(
+				INVALID_PARAMS_KEY_NAME, violation.getPropertyPath().toString(),
+				INVALID_PARAMS_KEY_VALUE, Objects.requireNonNullElse(violation.getInvalidValue(), PROVIDED_VALUE_WAS_NULL).toString(),
+				INVALID_PARAMS_KEY_REASON, violation.getMessage(),
+				INVALID_PARAMS_KEY_CONSTRAINT_PARAMETERS, buildParameters(violation).toList());
+	}
+
+	Stream<IssueParam> buildParameters(ConstraintViolation<?> violation) {
+		var dynamicPayload = getDynamicPayload(violation);
+		return Optional.ofNullable(violation.getConstraintDescriptor())
+				.map(ConstraintDescriptor::getAttributes)
+				.map(descr -> descr.entrySet().stream()
+						.filter(entry -> !IGNORABLE_CONSTRAINT_VIOLATION_ATTRIBUTES.contains(entry.getKey()))
+						.map(entryMap -> buildIssueParam(entryMap, dynamicPayload)))
+				.orElse(Stream.empty());
+	}
+
+	private IssueParam buildIssueParam(Entry<String, Object> entry, Optional<DynamicViolationParameter> dynamicValues) {
+		return IssueParam.builder().name(entry.getKey()).value(getValue(entry, dynamicValues)).build();
+	}
+
+	private String getValue(Entry<String, Object> entry, Optional<DynamicViolationParameter> dynamicValues) {
+		return dynamicValues
+				.map(DynamicViolationParameter::getMap)
+				.map(map -> map.get(entry.getKey()))
+				.filter(Objects::nonNull)
+				.map(String::valueOf)
+				.orElse(String.valueOf(entry.getValue()));
+	}
+
+	private Optional<DynamicViolationParameter> getDynamicPayload(ConstraintViolation<?> violation) {
+		HibernateConstraintViolation<?> hibernateViolation = violation.unwrap(HibernateConstraintViolation.class);
+		return Optional.ofNullable(hibernateViolation.getDynamicPayload(DynamicViolationParameter.class));
+	}
+}
diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/bescheid/BescheidCommandITCase.java b/alfa-service/src/test/java/de/ozgcloud/alfa/bescheid/BescheidCommandITCase.java
index d4c71d099ea22b5a27736889e0fb0aebff784a44..b85d323ef153890af71025bd9b886ab230a6a67f 100644
--- a/alfa-service/src/test/java/de/ozgcloud/alfa/bescheid/BescheidCommandITCase.java
+++ b/alfa-service/src/test/java/de/ozgcloud/alfa/bescheid/BescheidCommandITCase.java
@@ -52,9 +52,9 @@ public class BescheidCommandITCase {
 			String content = createInvalidRequestContent(BescheidTestFactory.createBuilder().beschiedenAm(null).build());
 
 			doRequest(content).andExpect(status().isUnprocessableEntity())
-					.andExpect(jsonPath("$.issues.length()").value(1))
-					.andExpect(jsonPath("$.issues.[0].field").value("command.body.beschiedenAm"))
-					.andExpect(jsonPath("$.issues.[0].messageCode").value(ValidationMessageCodes.FIELD_DATE_FORMAT_INVALID));
+					.andExpect(jsonPath("$.invalidParams.length()").value(1))
+					.andExpect(jsonPath("$.invalidParams[0].name").value("createCommand.command.body.beschiedenAm"))
+					.andExpect(jsonPath("$.invalidParams[0].reason").value(ValidationMessageCodes.FIELD_DATE_FORMAT_INVALID));
 		}
 
 		@ParameterizedTest
@@ -82,9 +82,9 @@ public class BescheidCommandITCase {
 			return mockMvc.perform(
 					post(CommandByRelationController.COMMAND_BY_RELATION_PATH, VorgangHeaderTestFactory.ID, VorgangHeaderTestFactory.ID,
 							VorgangHeaderTestFactory.VERSION)
-							.with(csrf())
-							.contentType(MediaType.APPLICATION_JSON)
-							.content(content));
+									.with(csrf())
+									.contentType(MediaType.APPLICATION_JSON)
+									.content(content));
 		}
 	}
 }
diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/common/binaryfile/BinaryFileControllerITCase.java b/alfa-service/src/test/java/de/ozgcloud/alfa/common/binaryfile/BinaryFileControllerITCase.java
index 16cd0b895439464f3feba0aeda52642d63985cc4..18ddf8ce29170a549e2bd63d0c080a5c6ebd3451 100644
--- a/alfa-service/src/test/java/de/ozgcloud/alfa/common/binaryfile/BinaryFileControllerITCase.java
+++ b/alfa-service/src/test/java/de/ozgcloud/alfa/common/binaryfile/BinaryFileControllerITCase.java
@@ -122,7 +122,7 @@ class BinaryFileControllerITCase {
 
 			void setTokenToSecuriyContext(String token) throws Exception {
 				mockMvc.perform(get(DownloadTokenController.DOWNLOAD_TOKEN_PATH + "?" + DownloadTokenController.PARAM_TOKEN + "=" + token)
-								.with(csrf()))
+						.with(csrf()))
 						.andExpect(status().isOk());
 			}
 		}
@@ -168,8 +168,8 @@ class BinaryFileControllerITCase {
 			@Test
 			void shouldReturnValidationMessage() throws Exception {
 				performRequest(createFile(MediaType.TEXT_PLAIN)).andExpect(status().isUnprocessableEntity())
-						.andExpect(jsonPath("$.issues.length()").value(1))
-						.andExpect(jsonPath("$.issues.[0].messageCode").value(ValidationMessageCodes.FIELD_FILE_CONTENT_TYPE_INVALID));
+						.andExpect(jsonPath("$.invalidParams.length()").value(1))
+						.andExpect(jsonPath("$.invalidParams[0].reason").value(ValidationMessageCodes.FIELD_FILE_CONTENT_TYPE_INVALID));
 			}
 
 			@Test
@@ -183,7 +183,7 @@ class BinaryFileControllerITCase {
 				return mockMvc.perform(multipart(
 						String.format("%s/%s/%s/file", BinaryFileController.PATH, VorgangHeaderTestFactory.ID,
 								UploadBinaryFileTestFactory.FIELD)).file(
-						file).with(csrf()));
+										file).with(csrf()));
 			}
 
 			private MockMultipartFile createFile(MediaType contentType) {
diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/common/binaryfile/BinaryFileITCase.java b/alfa-service/src/test/java/de/ozgcloud/alfa/common/binaryfile/BinaryFileITCase.java
index dcc9f9afcf7b622d9ac9e5d2f12a1a60b3bb34c2..6ab03aafe02d6aa07594f3622255b66b47e107d5 100644
--- a/alfa-service/src/test/java/de/ozgcloud/alfa/common/binaryfile/BinaryFileITCase.java
+++ b/alfa-service/src/test/java/de/ozgcloud/alfa/common/binaryfile/BinaryFileITCase.java
@@ -85,33 +85,33 @@ class BinaryFileITCase {
 			void shouldReturnConstraintViolationExceptionData() throws Exception {
 				var result = callEndpoint(TEST_FILE, BinaryFileTestFactory.FIELD);
 
-				result.andExpect(jsonPath("issues[0].field").value("uploadBinaryFileRequest"))
-						.andExpect(jsonPath("issues[0].messageCode").value("validation_field_file_size_exceeded"))
-						.andExpect(jsonPath("issues[0].message").value("validation_field_file_size_exceeded"))
-						.andExpect(jsonPath("issues[0].parameters[0].name").value("unit"))
-						.andExpect(jsonPath("issues[0].parameters[0].value").value(UploadBinaryFileSizeValidator.DEFAULT_UNIT_STRING));
+				result.andExpect(jsonPath("invalidParams[0].name").value("uploadFile.uploadBinaryFileRequest"))
+						.andExpect(jsonPath("invalidParams[0].reason").value("validation_field_file_size_exceeded"))
+						.andExpect(jsonPath("invalidParams[0].constraintParameters[0].name").value("unit"))
+						.andExpect(
+								jsonPath("invalidParams[0].constraintParameters[0].value").value(UploadBinaryFileSizeValidator.DEFAULT_UNIT_STRING));
 			}
 
 			@Test
 			void shouldContainsExceptionDataOnDefaultMaxSize() throws Exception {
 				var result = callEndpoint(TEST_FILE, BinaryFileTestFactory.FIELD);
 
-				result.andExpect(jsonPath("issues[0].parameters[1].name").value("max"))
-						.andExpect(jsonPath("issues[0].parameters[1].value").value("40"));
+				result.andExpect(jsonPath("invalidParams[0].constraintParameters[1].name").value("max"))
+						.andExpect(jsonPath("invalidParams[0].constraintParameters[1].value").value("40"));
 			}
 		}
 
 		@Nested
 		class TestForPostfachNachricht {
 
-			private final static String FIELD = "postfachNachrichtAttachment";
+			private static final String FIELD = "postfachNachrichtAttachment";
 
 			@Test
 			void shouldContainsExceptionDataOnPostfachNachrichtMaxSize() throws Exception {
 				var result = callEndpoint(TEST_FILE, FIELD);
 
-				result.andExpect(jsonPath("issues[0].parameters[1].name").value("max"))
-						.andExpect(jsonPath("issues[0].parameters[1].value").value("3"));
+				result.andExpect(jsonPath("invalidParams[0].constraintParameters[1].name").value("max"))
+						.andExpect(jsonPath("invalidParams[0].constraintParameters[1].value").value("3"));
 			}
 		}
 
diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/common/command/CommandControllerTest.java b/alfa-service/src/test/java/de/ozgcloud/alfa/common/command/CommandControllerTest.java
index 53f6ec125efb2914bb7754ff51211c646f904bbc..47da8200c2c2a6ab2465778f1110f3213e8c139b 100644
--- a/alfa-service/src/test/java/de/ozgcloud/alfa/common/command/CommandControllerTest.java
+++ b/alfa-service/src/test/java/de/ozgcloud/alfa/common/command/CommandControllerTest.java
@@ -43,6 +43,7 @@ import org.springframework.test.web.servlet.ResultActions;
 import org.springframework.test.web.servlet.setup.MockMvcBuilders;
 
 import de.ozgcloud.alfa.common.errorhandling.ExceptionController;
+import de.ozgcloud.alfa.common.errorhandling.ProblemDetailMapper;
 import de.ozgcloud.alfa.vorgang.VorgangHeaderTestFactory;
 import de.ozgcloud.common.test.TestUtils;
 
@@ -54,12 +55,14 @@ class CommandControllerTest {
 	private CommandService service;
 	@Mock
 	private CommandModelAssembler modelAssembler;
+	@Mock
+	private ProblemDetailMapper problemDetailMapper;
 
 	private MockMvc mockMvc;
 
 	@BeforeEach
 	void initTest() {
-		mockMvc = MockMvcBuilders.standaloneSetup(controller).setControllerAdvice(new ExceptionController()).build();
+		mockMvc = MockMvcBuilders.standaloneSetup(controller).setControllerAdvice(new ExceptionController(problemDetailMapper)).build();
 	}
 
 	@Nested
@@ -171,8 +174,8 @@ class CommandControllerTest {
 
 		private ResultActions doRequest() throws Exception {
 			return mockMvc.perform(get(CommandController.COMMANDS_PATH)
-					.param(CommandController.PARAM_PENDING, Boolean.toString(true))
-					.param(CommandController.PARAM_VORGANG_ID, VorgangHeaderTestFactory.ID))
+							.param(CommandController.PARAM_PENDING, Boolean.toString(true))
+							.param(CommandController.PARAM_VORGANG_ID, VorgangHeaderTestFactory.ID))
 					.andExpect(status().is2xxSuccessful());
 		}
 	}
diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/common/command/CommandITCase.java b/alfa-service/src/test/java/de/ozgcloud/alfa/common/command/CommandITCase.java
index 7ee0005a679ae552bd6e78cdc24ae00e6ab99213..3f396641e5d9aca17161d0276e9a0fe8d8521a44 100644
--- a/alfa-service/src/test/java/de/ozgcloud/alfa/common/command/CommandITCase.java
+++ b/alfa-service/src/test/java/de/ozgcloud/alfa/common/command/CommandITCase.java
@@ -126,9 +126,9 @@ public class CommandITCase {
 							.email(null).build());
 
 					doRequest(requestContent).andExpect(status().isUnprocessableEntity())
-							.andExpect(jsonPath("$.issues.length()").value(1))
-							.andExpect(jsonPath("$.issues.[0].field").value("command.redirectRequest.email"))
-							.andExpect(jsonPath("$.issues.[0].messageCode").value(ValidationMessageCodes.FIELD_IS_EMPTY));
+							.andExpect(jsonPath("$.invalidParams.length()").value(1))
+							.andExpect(jsonPath("$.invalidParams[0].name").value("createCommand.command.redirectRequest.email"))
+							.andExpect(jsonPath("$.invalidParams[0].reason").value(ValidationMessageCodes.FIELD_IS_EMPTY));
 				}
 			}
 
@@ -145,7 +145,7 @@ public class CommandITCase {
 							.build());
 
 					doRequest(requestContent).andExpect(status().isUnprocessableEntity())
-							.andExpect(jsonPath("$.issues.length()").value(2));
+							.andExpect(jsonPath("$.invalidParams.length()").value(2));
 				}
 			}
 
@@ -153,16 +153,16 @@ public class CommandITCase {
 			@Nested
 			class TestEmail {
 
-				private final String FIELD = "email";
+				private static final String FIELD = "email";
 
 				@Test
 				void shouldReturnErrorOnNullEMail() throws Exception {
 					var requestContent = buildRedirectRequestWithEmail(null);
 
 					doRequest(requestContent).andExpect(status().isUnprocessableEntity())
-							.andExpect(jsonPath("$.issues.length()").value(1))
-							.andExpect(jsonPath("$.issues.[0].field").value("command.redirectRequest." + FIELD))
-							.andExpect(jsonPath("$.issues.[0].messageCode").value(ValidationMessageCodes.FIELD_IS_EMPTY));
+							.andExpect(jsonPath("$.invalidParams.length()").value(1))
+							.andExpect(jsonPath("$.invalidParams[0].name").value("createCommand.command.redirectRequest." + FIELD))
+							.andExpect(jsonPath("$.invalidParams[0].reason").value(ValidationMessageCodes.FIELD_IS_EMPTY));
 				}
 
 				@Test
@@ -170,9 +170,9 @@ public class CommandITCase {
 					var requestContent = buildRedirectRequestWithEmail("local@@domain.com");
 
 					doRequest(requestContent).andExpect(status().isUnprocessableEntity())
-							.andExpect(jsonPath("$.issues.length()").value(1))
-							.andExpect(jsonPath("$.issues.[0].field").value("command.redirectRequest." + FIELD))
-							.andExpect(jsonPath("$.issues.[0].messageCode").value(ValidationMessageCodes.FIELD_INVALID));
+							.andExpect(jsonPath("$.invalidParams.length()").value(1))
+							.andExpect(jsonPath("$.invalidParams[0].name").value("createCommand.command.redirectRequest." + FIELD))
+							.andExpect(jsonPath("$.invalidParams[0].reason").value(ValidationMessageCodes.FIELD_INVALID));
 				}
 
 				private String buildRedirectRequestWithEmail(String eMail) {
@@ -191,13 +191,13 @@ public class CommandITCase {
 					var requestContent = buildRedirectRequestWithPassword(RandomStringUtils.randomAlphabetic(7));
 
 					doRequest(requestContent).andExpect(status().isUnprocessableEntity())
-							.andExpect(jsonPath("$.issues.length()").value(1))
-							.andExpect(jsonPath("$.issues.[0].field").value("command.redirectRequest." + FIELD))
-							.andExpect(jsonPath("$.issues.[0].messageCode").value(ValidationMessageCodes.FIELD_SIZE))
-							.andExpect(jsonPath("$.issues.[0].parameters[0].name").value("min"))
-							.andExpect(jsonPath("$.issues.[0].parameters[0].value").value(8))
-							.andExpect(jsonPath("$.issues.[0].parameters[1].name").value("max"))
-							.andExpect(jsonPath("$.issues.[0].parameters[1].value").value(40));
+							.andExpect(jsonPath("$.invalidParams.length()").value(1))
+							.andExpect(jsonPath("$.invalidParams[0].name").value("createCommand.command.redirectRequest." + FIELD))
+							.andExpect(jsonPath("$.invalidParams[0].reason").value(ValidationMessageCodes.FIELD_SIZE))
+							.andExpect(jsonPath("$.invalidParams[0].constraintParameters[0].name").value("min"))
+							.andExpect(jsonPath("$.invalidParams[0].constraintParameters[0].value").value(8))
+							.andExpect(jsonPath("$.invalidParams[0].constraintParameters[1].name").value("max"))
+							.andExpect(jsonPath("$.invalidParams[0].constraintParameters[1].value").value(40));
 				}
 
 				@Test
@@ -205,9 +205,9 @@ public class CommandITCase {
 					var requestContent = buildRedirectRequestWithPassword(RandomStringUtils.randomAlphabetic(41));
 
 					doRequest(requestContent).andExpect(status().isUnprocessableEntity())
-							.andExpect(jsonPath("$.issues.length()").value(1))
-							.andExpect(jsonPath("$.issues.[0].field").value("command.redirectRequest." + FIELD))
-							.andExpect(jsonPath("$.issues.[0].messageCode").value(ValidationMessageCodes.FIELD_SIZE));
+							.andExpect(jsonPath("$.invalidParams.length()").value(1))
+							.andExpect(jsonPath("$.invalidParams[0].name").value("createCommand.command.redirectRequest." + FIELD))
+							.andExpect(jsonPath("$.invalidParams[0].reason").value(ValidationMessageCodes.FIELD_SIZE));
 				}
 
 				private String buildRedirectRequestWithPassword(String password) {
@@ -245,9 +245,9 @@ public class CommandITCase {
 							.buildSendPostfachMailContent(PostfachMailTestFactory.createBuilder().subject(null).build());
 
 					doRequest(requestContent).andExpect(status().isUnprocessableEntity())
-							.andExpect(jsonPath("$.issues.length()").value(1))
-							.andExpect(jsonPath("$.issues.[0].field").value("command.body.subject"))
-							.andExpect(jsonPath("$.issues.[0].messageCode").value(ValidationMessageCodes.FIELD_IS_EMPTY));
+							.andExpect(jsonPath("$.invalidParams.length()").value(1))
+							.andExpect(jsonPath("$.invalidParams[0].name").value("createCommand.command.body.subject"))
+							.andExpect(jsonPath("$.invalidParams[0].reason").value(ValidationMessageCodes.FIELD_IS_EMPTY));
 				}
 
 				@Test
@@ -257,9 +257,9 @@ public class CommandITCase {
 									PostfachMailTestFactory.createBuilder().subject(RandomStringUtils.randomAlphanumeric(71)).build());
 
 					doRequest(requestContent).andExpect(status().isUnprocessableEntity())
-							.andExpect(jsonPath("$.issues.length()").value(1))
-							.andExpect(jsonPath("$.issues.[0].field").value("command.body.subject"))
-							.andExpect(jsonPath("$.issues.[0].messageCode").value(ValidationMessageCodes.FIELD_MAX_SIZE));
+							.andExpect(jsonPath("$.invalidParams.length()").value(1))
+							.andExpect(jsonPath("$.invalidParams[0].name").value("createCommand.command.body.subject"))
+							.andExpect(jsonPath("$.invalidParams[0].reason").value(ValidationMessageCodes.FIELD_MAX_SIZE));
 				}
 
 				@Test
@@ -280,9 +280,9 @@ public class CommandITCase {
 							.buildSendPostfachMailContent(PostfachMailTestFactory.createBuilder().mailBody(null).build());
 
 					doRequest(request).andExpect(status().isUnprocessableEntity())
-							.andExpect(jsonPath("$.issues.length()").value(1))
-							.andExpect(jsonPath("$.issues.[0].field").value("command.body.mailBody"))
-							.andExpect(jsonPath("$.issues.[0].messageCode").value(ValidationMessageCodes.FIELD_IS_EMPTY));
+							.andExpect(jsonPath("$.invalidParams.length()").value(1))
+							.andExpect(jsonPath("$.invalidParams[0].name").value("createCommand.command.body.mailBody"))
+							.andExpect(jsonPath("$.invalidParams[0].reason").value(ValidationMessageCodes.FIELD_IS_EMPTY));
 				}
 
 				@Test
@@ -299,9 +299,9 @@ public class CommandITCase {
 		ResultActions doRequest(String content) throws Exception {
 			return mockMvc.perform(post("/api/vorgangs/" + CommandTestFactory.VORGANG_ID + "/relations/" + CommandTestFactory.RELATION_ID + "/"
 					+ CommandTestFactory.RELATION_VERSION + "/commands")
-					.with(csrf())
-					.contentType(MediaType.APPLICATION_JSON)
-					.content(content));
+							.with(csrf())
+							.contentType(MediaType.APPLICATION_JSON)
+							.content(content));
 		}
 	}
 }
\ No newline at end of file
diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/common/errorhandling/ExceptionControllerTest.java b/alfa-service/src/test/java/de/ozgcloud/alfa/common/errorhandling/ExceptionControllerTest.java
index 489f0a8f4f2504e203d81504db92d12efc76f777..50a0b2d1af3cce26dfd38934071b5cf48264c048 100644
--- a/alfa-service/src/test/java/de/ozgcloud/alfa/common/errorhandling/ExceptionControllerTest.java
+++ b/alfa-service/src/test/java/de/ozgcloud/alfa/common/errorhandling/ExceptionControllerTest.java
@@ -27,7 +27,6 @@ import static org.assertj.core.api.Assertions.*;
 import static org.mockito.Mockito.*;
 
 import java.util.Collections;
-import java.util.Map;
 
 import jakarta.validation.ConstraintViolationException;
 
@@ -36,10 +35,14 @@ import org.junit.jupiter.api.DisplayName;
 import org.junit.jupiter.api.Nested;
 import org.junit.jupiter.api.Test;
 import org.mockito.InjectMocks;
+import org.mockito.Mock;
 import org.mockito.Spy;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ProblemDetail;
 import org.springframework.security.access.AccessDeniedException;
 
-import de.ozgcloud.alfa.common.binaryfile.DynamicViolationParameter;
+import com.thedeanda.lorem.LoremIpsum;
+
 import de.ozgcloud.alfa.common.command.LegacyOrder;
 import de.ozgcloud.common.errorhandling.TechnicalException;
 
@@ -49,6 +52,9 @@ class ExceptionControllerTest {
 	@InjectMocks
 	private ExceptionController exceptionController;
 
+	@Mock
+	private ProblemDetailMapper problemDetailMapper;
+
 	@Nested
 	class TestHandleFunctionalException {
 
@@ -162,79 +168,42 @@ class ExceptionControllerTest {
 	@Nested
 	class TestContraintValidationException {
 
-		private final ConstraintViolationException exception = new ConstraintViolationException(ExceptionTestFactory.MESSAGE,
-				Collections.singleton(ExceptionTestFactory.buildMockedConstraintViolation()));
-
-		@BeforeEach
-		void mockExceptionId() {
-			doReturn(ExceptionTestFactory.EXCEPTION_ID).when(exceptionController).createExceptionId();
-		}
-
-		@Test
-		void shouldHaveField() {
-			var error = handleException();
-
-			assertThat(error.getIssues()).hasSize(1);
-			assertThat(error.getIssues().get(0).getField()).isEqualTo(ExceptionTestFactory.PATH_FIELD);
-		}
-
-		@Test
-		void shouldHaveMessageCode() {
-			var error = handleException();
-
-			assertThat(error.getIssues()).hasSize(1);
-			assertThat(error.getIssues().get(0).getMessageCode()).isEqualTo(ExceptionTestFactory.MESSAGE_CODE);
-		}
-
-		@Test
-		void shouldHaveMessage() {
-			var error = handleException();
-
-			assertThat(error.getIssues()).hasSize(1);
-			assertThat(error.getIssues().get(0).getMessage()).isEqualTo(ExceptionTestFactory.MESSAGE);
-		}
-
-		@Test
-		void shouldHaveExceptionId() {
-			var error = handleException();
+		@Nested
+		class TestHandleConstraintViolationException {
+			private final String exceptionMessage = LoremIpsum.getInstance().getWords(5);
 
-			assertThat(error.getIssues().get(0).getExceptionId()).isEqualTo(ExceptionTestFactory.EXCEPTION_ID);
-		}
+			private final ConstraintViolationException exception = new ConstraintViolationException(exceptionMessage,
+					Collections.singleton(ExceptionTestFactory.buildMockedConstraintViolation()));
 
-		@Test
-		void shouldHaveIssueParameter() {
-			var error = handleException();
+			@Test
+			void shouldGetMessageWithExceptionId() {
+				handleException();
 
-			var issueParameter = error.getIssues().get(0).getParameters().get(0);
-			assertThat(issueParameter.getName()).isEqualTo(ExceptionTestFactory.PARAM_NAME);
-			assertThat(issueParameter.getValue()).isEqualTo(ExceptionTestFactory.PARAM_DYNAMIC_VALUE);
-		}
+				verify(problemDetailMapper).buildMessageWithExceptionId(exception);
+			}
 
-		@Nested
-		class TestWithDynamicPayload {
+			@Test
+			void shouldBuildConstraintViolationProblemDetail() {
+				handleException();
 
-			private final DynamicViolationParameter dynamicViolationParameter = DynamicViolationParameter.builder()
-					.map(Map.of(ExceptionTestFactory.PARAM_NAME, ExceptionTestFactory.PARAM_DYNAMIC_VALUE)).build();
-			private final ConstraintViolationException exceptionWithDynamicPayload = new ConstraintViolationException(ExceptionTestFactory.MESSAGE,
-					Collections.singleton(ExceptionTestFactory.buildMockedConstraintViolationWithDynamicPayload(dynamicViolationParameter)));
+				verify(problemDetailMapper).fromConstraintViolationException(exception);
+			}
 
 			@Test
-			void shouldHaveReplacedParams() {
-				var error = handleExceptionWithDynamicPayload();
+			void shouldReturnBuiltProblemDetail() {
+				var expectedProblemDetail = ProblemDetail.forStatusAndDetail(HttpStatus.UNPROCESSABLE_ENTITY, exceptionMessage);
+				when(problemDetailMapper.fromConstraintViolationException(exception)).thenReturn(expectedProblemDetail);
+
+				var problemDetail = handleException();
 
-				var issueParameter = error.getIssues().get(0).getParameters().get(0);
-				assertThat(issueParameter.getName()).isEqualTo(ExceptionTestFactory.PARAM_NAME);
-				assertThat(issueParameter.getValue()).isEqualTo(ExceptionTestFactory.PARAM_DYNAMIC_VALUE);
+				assertThat(problemDetail).isEqualTo(expectedProblemDetail);
 			}
 
-			private ApiError handleExceptionWithDynamicPayload() {
-				return exceptionController.handleConstraintViolationException(exceptionWithDynamicPayload);
+			private ProblemDetail handleException() {
+				return exceptionController.handleConstraintViolationException(exception);
 			}
 		}
 
-		private ApiError handleException() {
-			return exceptionController.handleConstraintViolationException(exception);
-		}
 	}
 
 	@Nested
diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/common/errorhandling/ExceptionTestFactory.java b/alfa-service/src/test/java/de/ozgcloud/alfa/common/errorhandling/ExceptionTestFactory.java
index d96c42787390b1b99df6bd412efce278c3dd7335..19cdbe389dc959ade05e069b6b820513c980d3c2 100644
--- a/alfa-service/src/test/java/de/ozgcloud/alfa/common/errorhandling/ExceptionTestFactory.java
+++ b/alfa-service/src/test/java/de/ozgcloud/alfa/common/errorhandling/ExceptionTestFactory.java
@@ -48,26 +48,26 @@ public class ExceptionTestFactory {
 	static final String PARAM_DYNAMIC_VALUE = "20";
 	static final String MESSAGE = LoremIpsum.getInstance().getWords(5);
 	static final String MESSAGE_CODE = "message.code";
-	private static final String PATH_SUFFIX = "createCommandByRelation";
+	private static final String PATH_PREFIX = "createCommandByRelation";
 	static final String PATH_FIELD = "command.wiedervorlage.betreff";
-	private static final String PATH = PATH_SUFFIX + "." + PATH_FIELD;
+	public static final String PATH = PATH_PREFIX + "." + PATH_FIELD;
 
 	public static ConstraintViolation<?> buildMockedConstraintViolation() {
 		return ExceptionTestFactory.buildMockedConstraintViolationWithDynamicPayload(null);
 	}
 
-	@SuppressWarnings({ "rawtypes", "unchecked" })
+	@SuppressWarnings({ "unchecked" })
 	public static <T> ConstraintViolation<T> buildMockedConstraintViolationWithDynamicPayload(DynamicViolationParameter dynamicViolationParameter) {
-		ConstraintViolation violation = mock(ConstraintViolation.class);
-		HibernateConstraintViolation hibernateViolation = mock(HibernateConstraintViolation.class);
-		ConstraintDescriptor constraintDescriptor = mock(ConstraintDescriptor.class);
+		var violation = mock(ConstraintViolation.class);
+		var hibernateViolation = mock(HibernateConstraintViolation.class);
+		var constraintDescriptor = mock(ConstraintDescriptor.class);
 
 		var path = mock(Path.class);
 		when(path.toString()).thenReturn(PATH);
 		when(violation.getPropertyPath()).thenReturn(path);
-		when(violation.getMessageTemplate()).thenReturn("{" + MESSAGE_CODE + "}");
 		when(violation.getMessage()).thenReturn(MESSAGE);
 		when(violation.getConstraintDescriptor()).thenReturn(constraintDescriptor);
+		when(violation.getInvalidValue()).thenReturn(PARAM_VALUE);
 		when(constraintDescriptor.getAttributes()).thenReturn(Map.of(PARAM_NAME, PARAM_DYNAMIC_VALUE));
 		when(violation.unwrap(any())).thenReturn(hibernateViolation);
 		when(hibernateViolation.getDynamicPayload(any())).thenReturn(dynamicViolationParameter);
diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/common/errorhandling/IssueParamTestFactory.java b/alfa-service/src/test/java/de/ozgcloud/alfa/common/errorhandling/IssueParamTestFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..2a9a035c179a40230996e0d97cc72ebbb0df7366
--- /dev/null
+++ b/alfa-service/src/test/java/de/ozgcloud/alfa/common/errorhandling/IssueParamTestFactory.java
@@ -0,0 +1,17 @@
+package de.ozgcloud.alfa.common.errorhandling;
+
+import de.ozgcloud.alfa.common.errorhandling.IssueParam.IssueParamBuilder;
+
+public class IssueParamTestFactory {
+	public static final String PARAM_NAME = ExceptionTestFactory.PARAM_NAME;
+	public static final String PARAM_DYNAMIC_VALUE = ExceptionTestFactory.PARAM_DYNAMIC_VALUE;
+
+	public static IssueParam create() {
+		return createBuilder()
+				.build();
+	}
+
+	public static IssueParamBuilder createBuilder() {
+		return IssueParam.builder().name(PARAM_NAME).value(PARAM_DYNAMIC_VALUE);
+	}
+}
diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/common/errorhandling/ProblemDetailMapperTest.java b/alfa-service/src/test/java/de/ozgcloud/alfa/common/errorhandling/ProblemDetailMapperTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..b55e6f4ee9a7f15c902446f1846893ca4614f3b0
--- /dev/null
+++ b/alfa-service/src/test/java/de/ozgcloud/alfa/common/errorhandling/ProblemDetailMapperTest.java
@@ -0,0 +1,313 @@
+package de.ozgcloud.alfa.common.errorhandling;
+
+import static org.assertj.core.api.Assertions.*;
+import static org.mockito.ArgumentMatchers.*;
+import static org.mockito.Mockito.*;
+
+import java.util.AbstractMap.SimpleEntry;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.UUID;
+import java.util.stream.Stream;
+
+import jakarta.validation.ConstraintViolation;
+import jakarta.validation.ConstraintViolationException;
+import jakarta.validation.metadata.ConstraintDescriptor;
+
+import org.hibernate.validator.engine.HibernateConstraintViolation;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Nested;
+import org.junit.jupiter.api.Test;
+import org.mockito.Mock;
+import org.mockito.Spy;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ProblemDetail;
+
+import com.thedeanda.lorem.LoremIpsum;
+
+import de.ozgcloud.alfa.common.binaryfile.DynamicViolationParameter;
+import de.ozgcloud.common.errorhandling.ExceptionUtil;
+
+class ProblemDetailMapperTest {
+
+	@Spy
+	private ProblemDetailMapper mapper;
+
+	@Nested
+	class TestFromConstraintViolationException {
+		private final String exceptionMessage = LoremIpsum.getInstance().getWords(5);
+		private final Set<ConstraintViolation<?>> violations = Collections.singleton(ExceptionTestFactory.buildMockedConstraintViolation());
+		private final ConstraintViolationException exception = new ConstraintViolationException(exceptionMessage, violations);
+		private final String message = LoremIpsum.getInstance().getWords(5);
+
+		@BeforeEach
+		void mockMapper() {
+			doReturn(message).when(mapper).buildMessageWithExceptionId(exception);
+		}
+
+		@Test
+		void shouldGetMessageWithExcpetionId() {
+			callMapper();
+
+			verify(mapper).buildMessageWithExceptionId(exception);
+		}
+
+		@Test
+		void shouldHaveStatusUnprocessableEntity() {
+			var problemDetail = callMapper();
+
+			assertThat(problemDetail.getStatus()).isEqualTo(HttpStatus.UNPROCESSABLE_ENTITY.value());
+		}
+
+		@Test
+		void shouldHaveMessageInDetail() {
+			var problemDetail = callMapper();
+
+			assertThat(problemDetail.getDetail()).contains(message);
+		}
+
+		@Test
+		void shouldGetDetailedViolationList() {
+			callMapper();
+
+			verify(mapper).buildInvalidParams(violations);
+		}
+
+		@Test
+		void shouldSetPropertyInvalidParams() {
+			var expectedInvalidParamsValue = Map.of();
+			doReturn(Stream.of(expectedInvalidParamsValue)).when(mapper).buildInvalidParams(violations);
+
+			var problemDetail = callMapper();
+
+			assertThat(problemDetail.getProperties())
+					.containsExactly(new SimpleEntry<String, Object>(ProblemDetailMapper.INVALID_PARAMS, List.of(expectedInvalidParamsValue)));
+		}
+
+		private ProblemDetail callMapper() {
+			return mapper.fromConstraintViolationException(exception);
+		}
+	}
+
+	@Nested
+	class TestBuildMessageWithExceptionId {
+
+		private final String exceptionMessage = LoremIpsum.getInstance().getWords(5);
+		private final String exceptionId = UUID.randomUUID().toString();
+		private final ConstraintViolationException exception = new ConstraintViolationException(exceptionMessage, null);
+
+		@BeforeEach
+		void mockCreateExcpetionId() {
+			doReturn(exceptionId).when(mapper).createExceptionId();
+		}
+
+		@Test
+		void shouldCreateExceptionId() {
+			callMapper();
+
+			verify(mapper).createExceptionId();
+		}
+
+		@Test
+		void shouldFormatMessageWithExceptionId() {
+			var messageWithId = callMapper();
+
+			assertThat(messageWithId).isEqualTo(ExceptionUtil.formatMessageWithExceptionId(exceptionMessage, exceptionId));
+		}
+
+		private String callMapper() {
+			return mapper.buildMessageWithExceptionId(exception);
+		}
+	}
+
+	@Nested
+	class TestBuildInvalidParams {
+
+		@Nested
+		class OnViolations {
+			private final Set<ConstraintViolation<?>> violations = Set.of(ExceptionTestFactory.buildMockedConstraintViolation(),
+					ExceptionTestFactory.buildMockedConstraintViolation());
+
+			@Test
+			void shouldCallBuildDetailedViolation() {
+				callMapper().toList();
+
+				violations.forEach(violation -> verify(mapper).buildDetailedViolation(violation));
+			}
+
+			@Test
+			void shouldReturnListWithDetailedViolations() {
+				Map<String, Object> detailsMap = Map.of(LoremIpsum.getInstance().getWords(1), LoremIpsum.getInstance().getWords(1));
+				violations.forEach(violation -> doReturn(detailsMap).when(mapper).buildDetailedViolation(violation));
+
+				var detailedViolations = callMapper();
+
+				assertThat(detailedViolations).containsExactly(detailsMap, detailsMap);
+			}
+
+			private Stream<Map<String, Object>> callMapper() {
+				return mapper.buildInvalidParams(violations);
+			}
+		}
+
+		@Nested
+		class OnEmptyViolations {
+			private final Set<ConstraintViolation<?>> violations = Collections.emptySet();
+
+			@Test
+			void shouldCallNotBuildDetailedViolation() {
+				callMapper();
+
+				verify(mapper, never()).buildDetailedViolation(any());
+			}
+
+			@Test
+			void shouldReturnListWithDetailedViolations() {
+				var detailedViolations = callMapper();
+
+				assertThat(detailedViolations).isEmpty();
+			}
+
+			private Stream<Map<String, Object>> callMapper() {
+				return mapper.buildInvalidParams(violations);
+			}
+		}
+	}
+
+	@Nested
+	class TestBuildDetailedViolation {
+		private final ConstraintViolation<?> violation = ExceptionTestFactory.buildMockedConstraintViolation();
+
+		@Test
+		void shouldContainFieldName() {
+			var expectedEntry = new SimpleEntry<>(ProblemDetailMapper.INVALID_PARAMS_KEY_NAME, ExceptionTestFactory.PATH);
+
+			var detailedViolation = callMapper();
+
+			assertThat(detailedViolation).contains(expectedEntry);
+		}
+
+		@Test
+		void shouldContainValue() {
+			var expectedEntry = new SimpleEntry<>(ProblemDetailMapper.INVALID_PARAMS_KEY_VALUE, ExceptionTestFactory.PARAM_VALUE);
+
+			var detailedViolation = callMapper();
+
+			assertThat(detailedViolation).contains(expectedEntry);
+		}
+
+		@Test
+		void shouldHandleNullValue() {
+			when(violation.getInvalidValue()).thenReturn(null);
+			var expectedEntry = new SimpleEntry<>(ProblemDetailMapper.INVALID_PARAMS_KEY_VALUE,
+					ProblemDetailMapper.PROVIDED_VALUE_WAS_NULL);
+
+			var detailedViolation = callMapper();
+
+			assertThat(detailedViolation).contains(expectedEntry);
+		}
+
+		@Test
+		void shouldContainReason() {
+			var expectedEntry = new SimpleEntry<>(ProblemDetailMapper.INVALID_PARAMS_KEY_REASON, ExceptionTestFactory.MESSAGE);
+
+			var detailedViolation = callMapper();
+
+			assertThat(detailedViolation).contains(expectedEntry);
+		}
+
+		@Test
+		void shouldBuildParameters() {
+			callMapper();
+
+			verify(mapper).buildParameters(violation);
+		}
+
+		@Test
+		void shouldContainConstraintParameters() {
+			var issueParameter = IssueParamTestFactory.create();
+			doReturn(Stream.of(issueParameter)).when(mapper).buildParameters(violation);
+			var expectedEntry = new SimpleEntry<String, Object>(ProblemDetailMapper.INVALID_PARAMS_KEY_CONSTRAINT_PARAMETERS,
+					List.of(issueParameter));
+
+			var detailedViolation = callMapper();
+
+			assertThat(detailedViolation).contains(expectedEntry);
+		}
+
+		private Map<String, Object> callMapper() {
+			return mapper.buildDetailedViolation(violation);
+		}
+	}
+
+	@Nested
+	class TestBuildParameters {
+
+		@Mock
+		private ConstraintViolation<?> violation;
+
+		@Mock
+		@SuppressWarnings("rawtypes")
+		private ConstraintDescriptor constraintDescriptor;
+
+		@Mock
+		@SuppressWarnings("rawtypes")
+		private HibernateConstraintViolation hibernateConstraintViolation;
+
+		@SuppressWarnings("unchecked")
+		@BeforeEach
+		void setUpViolationMocks() {
+			when(violation.getConstraintDescriptor()).thenReturn(constraintDescriptor);
+			when(violation.unwrap(HibernateConstraintViolation.class)).thenReturn(hibernateConstraintViolation);
+			when(constraintDescriptor.getAttributes())
+					.thenReturn(Map.of(ExceptionTestFactory.PARAM_NAME, ExceptionTestFactory.PARAM_DYNAMIC_VALUE));
+		}
+
+		@Nested
+		class OnNonDynamicPayload {
+
+			@Test
+			void shouldBuildIssueParam() {
+				var issueParams = mapper.buildParameters(violation);
+
+				assertThat(issueParams).usingRecursiveFieldByFieldElementComparator().contains(IssueParamTestFactory.create());
+			}
+
+		}
+
+		@Nested
+		class TestWithDynamicPayload {
+
+			@SuppressWarnings("unchecked")
+			@Test
+			void shouldHaveReplacedIssueParameterName() {
+				var dynamicValue = LoremIpsum.getInstance().getWords(1);
+				var dynamicViolationParameter = DynamicViolationParameter.builder()
+						.map(Map.of(ExceptionTestFactory.PARAM_NAME, dynamicValue))
+						.build();
+				when(hibernateConstraintViolation.getDynamicPayload(DynamicViolationParameter.class)).thenReturn(dynamicViolationParameter);
+				var expectedIssueParam = IssueParamTestFactory.createBuilder().value(dynamicValue).build();
+
+				var issueParams = mapper.buildParameters(violation);
+
+				assertThat(issueParams).usingRecursiveFieldByFieldElementComparator().contains(expectedIssueParam);
+			}
+
+			@SuppressWarnings("unchecked")
+			@Test
+			void shouldIgnoreKeyNotPresentInEntry() {
+				var dynamicViolationParameter = DynamicViolationParameter.builder()
+						.map(Map.of(LoremIpsum.getInstance().getWords(1), LoremIpsum.getInstance().getWords(1)))
+						.build();
+				when(hibernateConstraintViolation.getDynamicPayload(DynamicViolationParameter.class)).thenReturn(dynamicViolationParameter);
+				var expectedIssueParam = IssueParamTestFactory.create();
+
+				var issueParams = mapper.buildParameters(violation);
+
+				assertThat(issueParams).usingRecursiveFieldByFieldElementComparator().contains(expectedIssueParam);
+			}
+		}
+	}
+}
diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/kommentar/KommentarCommandITCase.java b/alfa-service/src/test/java/de/ozgcloud/alfa/kommentar/KommentarCommandITCase.java
index 87d5be0da2eae911f865f47380307fe8a7fa61b5..0eed2bf6a4c58bdce7d81ccb29f1de9d40ad372d 100644
--- a/alfa-service/src/test/java/de/ozgcloud/alfa/kommentar/KommentarCommandITCase.java
+++ b/alfa-service/src/test/java/de/ozgcloud/alfa/kommentar/KommentarCommandITCase.java
@@ -107,9 +107,9 @@ class KommentarCommandITCase {
 				String content = buildContentWithText(null);
 
 				doRequestByKommentarId(content).andExpect(status().isUnprocessableEntity())
-						.andExpect(jsonPath("$.issues.length()").value(1))
-						.andExpect(jsonPath("$.issues.[0].field").value("kommentar.text"))
-						.andExpect(jsonPath("$.issues.[0].messageCode").value(ValidationMessageCodes.FIELD_IS_EMPTY));
+						.andExpect(jsonPath("$.invalidParams.length()").value(1))
+						.andExpect(jsonPath("$.invalidParams[0].name").value("editKommentar.kommentar.text"))
+						.andExpect(jsonPath("$.invalidParams[0].reason").value(ValidationMessageCodes.FIELD_IS_EMPTY));
 			}
 
 			@SneakyThrows
@@ -119,7 +119,7 @@ class KommentarCommandITCase {
 				String content = buildContentWithText(StringUtils.EMPTY);
 
 				doRequestByKommentarId(content).andExpect(status().isUnprocessableEntity())
-						.andExpect(jsonPath("$.issues.[0].field").value("kommentar.text"));
+						.andExpect(jsonPath("$.invalidParams[0].name").value("editKommentar.kommentar.text"));
 
 			}
 
@@ -130,7 +130,7 @@ class KommentarCommandITCase {
 				String content = buildContentWithText(StringUtils.EMPTY);
 
 				doRequestByKommentarId(content).andExpect(status().isUnprocessableEntity())
-						.andExpect(jsonPath("$.issues[0].parameters.length()").value(2));
+						.andExpect(jsonPath("$.invalidParams[0].constraintParameters.length()").value(2));
 			}
 
 			private String buildContentWithText(String text) {
@@ -190,9 +190,9 @@ class KommentarCommandITCase {
 				String content = buildContentWithText(null);
 
 				doRequestByVorgangId(content).andExpect(status().isUnprocessableEntity())
-						.andExpect(jsonPath("$.issues.length()").value(1))
-						.andExpect(jsonPath("$.issues.[0].field").value("kommentar.text"))
-						.andExpect(jsonPath("$.issues.[0].messageCode").value(ValidationMessageCodes.FIELD_IS_EMPTY));
+						.andExpect(jsonPath("$.invalidParams.length()").value(1))
+						.andExpect(jsonPath("$.invalidParams.[0].name").value("createKommentar.kommentar.text"))
+						.andExpect(jsonPath("$.invalidParams.[0].reason").value(ValidationMessageCodes.FIELD_IS_EMPTY));
 			}
 
 			@SneakyThrows
@@ -202,7 +202,7 @@ class KommentarCommandITCase {
 				String content = buildContentWithText(StringUtils.EMPTY);
 
 				doRequestByVorgangId(content).andExpect(status().isUnprocessableEntity())
-						.andExpect(jsonPath("$.issues.[0].field").value("kommentar.text"));
+						.andExpect(jsonPath("$.invalidParams.[0].name").value("createKommentar.kommentar.text"));
 
 			}
 
@@ -213,7 +213,7 @@ class KommentarCommandITCase {
 				String content = buildContentWithText(StringUtils.EMPTY);
 
 				doRequestByVorgangId(content).andExpect(status().isUnprocessableEntity())
-						.andExpect(jsonPath("$.issues[0].parameters.length()").value(2));
+						.andExpect(jsonPath("$.invalidParams[0].constraintParameters.length()").value(2));
 			}
 
 			private String buildContentWithText(String text) {
diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/loeschanforderung/LoeschAnforderungByVorgangControllerTest.java b/alfa-service/src/test/java/de/ozgcloud/alfa/loeschanforderung/LoeschAnforderungByVorgangControllerTest.java
index 63101495e8422e6f26a9be4389fe19c995f30853..c27019e2998e2ef073b0caf0c15a8daf07f15e8f 100644
--- a/alfa-service/src/test/java/de/ozgcloud/alfa/loeschanforderung/LoeschAnforderungByVorgangControllerTest.java
+++ b/alfa-service/src/test/java/de/ozgcloud/alfa/loeschanforderung/LoeschAnforderungByVorgangControllerTest.java
@@ -26,6 +26,7 @@ import de.ozgcloud.alfa.common.command.CommandOrder;
 import de.ozgcloud.alfa.common.command.CommandTestFactory;
 import de.ozgcloud.alfa.common.command.CreateCommand;
 import de.ozgcloud.alfa.common.errorhandling.ExceptionController;
+import de.ozgcloud.alfa.common.errorhandling.ProblemDetailMapper;
 import de.ozgcloud.alfa.loeschanforderung.LoeschAnforderungController.LoeschAnforderungByVorgangController;
 import de.ozgcloud.alfa.vorgang.VorgangController;
 import de.ozgcloud.alfa.vorgang.VorgangHeaderTestFactory;
@@ -44,11 +45,14 @@ class LoeschAnforderungByVorgangControllerTest {
 	@Mock
 	private VorgangController vorgangController;
 
+	@Mock
+	private ProblemDetailMapper problemDetailMapper;
+
 	private MockMvc mockMvc;
 
 	@BeforeEach
 	void init() {
-		mockMvc = MockMvcBuilders.standaloneSetup(controller).setControllerAdvice(new ExceptionController()).build();
+		mockMvc = MockMvcBuilders.standaloneSetup(controller).setControllerAdvice(new ExceptionController(problemDetailMapper)).build();
 	}
 
 	@DisplayName("Create LoeschAnforderung")
@@ -93,7 +97,7 @@ class LoeschAnforderungByVorgangControllerTest {
 		private ResultActions doRequest() throws Exception {
 			var requestBody = CommandTestFactory.buildCreateVorgangCommandContent(CommandOrder.VORGANG_ZUM_LOESCHEN_MARKIEREN.name());
 			return mockMvc.perform(post(LoeschAnforderungByVorgangController.BASE_PATH,
-					VorgangHeaderTestFactory.ID, VorgangHeaderTestFactory.VERSION)
+							VorgangHeaderTestFactory.ID, VorgangHeaderTestFactory.VERSION)
 							.content(requestBody).contentType(MediaType.APPLICATION_JSON).characterEncoding(StandardCharsets.UTF_8.name()))
 					.andExpect(status().isCreated());
 		}
diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/loeschanforderung/LoeschAnforderungCommandControllerTest.java b/alfa-service/src/test/java/de/ozgcloud/alfa/loeschanforderung/LoeschAnforderungCommandControllerTest.java
index 392b53911f57a0836a38022192c77c7d6b72411c..ad87a8ced732c2ec48ef91262ce188a9647aabf3 100644
--- a/alfa-service/src/test/java/de/ozgcloud/alfa/loeschanforderung/LoeschAnforderungCommandControllerTest.java
+++ b/alfa-service/src/test/java/de/ozgcloud/alfa/loeschanforderung/LoeschAnforderungCommandControllerTest.java
@@ -3,8 +3,8 @@ package de.ozgcloud.alfa.loeschanforderung;
 import static de.ozgcloud.alfa.common.command.CommandController.*;
 import static org.assertj.core.api.Assertions.*;
 import static org.hamcrest.CoreMatchers.*;
-import static org.mockito.ArgumentMatchers.*;
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.*;
 import static org.mockito.Mockito.*;
 import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
@@ -40,6 +40,7 @@ import de.ozgcloud.alfa.common.command.CreateCommand;
 import de.ozgcloud.alfa.common.command.LegacyOrder;
 import de.ozgcloud.alfa.common.command.StatusPatch;
 import de.ozgcloud.alfa.common.errorhandling.ExceptionController;
+import de.ozgcloud.alfa.common.errorhandling.ProblemDetailMapper;
 import de.ozgcloud.alfa.vorgang.VorgangController;
 import de.ozgcloud.alfa.vorgang.VorgangHeaderTestFactory;
 import de.ozgcloud.alfa.vorgang.VorgangWithEingang;
@@ -64,11 +65,14 @@ class LoeschAnforderungCommandControllerTest {
 	@Mock
 	private CommandController commandController;
 
+	@Mock
+	private ProblemDetailMapper problemDetailMapper;
+
 	private MockMvc mockMvc;
 
 	@BeforeEach
 	void init() {
-		mockMvc = MockMvcBuilders.standaloneSetup(controller).setControllerAdvice(new ExceptionController()).build();
+		mockMvc = MockMvcBuilders.standaloneSetup(controller).setControllerAdvice(new ExceptionController(problemDetailMapper)).build();
 	}
 
 	@DisplayName("Create command")
diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/loeschanforderung/LoeschAnforderungControllerTest.java b/alfa-service/src/test/java/de/ozgcloud/alfa/loeschanforderung/LoeschAnforderungControllerTest.java
index a0ea03964f79264344bb89b24f16bddcc4cf0ed1..0ccd8259172c85ae64c5b55356d9eadc30e2b9a1 100644
--- a/alfa-service/src/test/java/de/ozgcloud/alfa/loeschanforderung/LoeschAnforderungControllerTest.java
+++ b/alfa-service/src/test/java/de/ozgcloud/alfa/loeschanforderung/LoeschAnforderungControllerTest.java
@@ -17,6 +17,7 @@ import org.springframework.test.web.servlet.setup.MockMvcBuilders;
 
 import de.ozgcloud.alfa.common.UserProfileUrlProvider;
 import de.ozgcloud.alfa.common.errorhandling.ExceptionController;
+import de.ozgcloud.alfa.common.errorhandling.ProblemDetailMapper;
 import lombok.SneakyThrows;
 
 class LoeschAnforderungControllerTest {
@@ -30,11 +31,14 @@ class LoeschAnforderungControllerTest {
 	@Mock
 	private LoeschAnforderungModelAssembler modelAssembler;
 
+	@Mock
+	private ProblemDetailMapper problemDetailMapper;
+
 	private MockMvc mockMvc;
 
 	@BeforeEach
 	void init() {
-		mockMvc = MockMvcBuilders.standaloneSetup(controller).setControllerAdvice(new ExceptionController()).build();
+		mockMvc = MockMvcBuilders.standaloneSetup(controller).setControllerAdvice(new ExceptionController(problemDetailMapper)).build();
 	}
 
 	@Nested
diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/wiedervorlage/WiedervorlageCommandITCase.java b/alfa-service/src/test/java/de/ozgcloud/alfa/wiedervorlage/WiedervorlageCommandITCase.java
index 88a17b72ba185204edb3514e4a2bfcd90bcf53a6..d0328ea3258d380bf799e934d07e4f20227c4528 100644
--- a/alfa-service/src/test/java/de/ozgcloud/alfa/wiedervorlage/WiedervorlageCommandITCase.java
+++ b/alfa-service/src/test/java/de/ozgcloud/alfa/wiedervorlage/WiedervorlageCommandITCase.java
@@ -103,9 +103,9 @@ class WiedervorlageCommandITCase {
 				String content = buildContentWithBetreff(null);
 
 				doRequest(content).andExpect(status().isUnprocessableEntity())
-						.andExpect(jsonPath("$.issues.length()").value(1))
-						.andExpect(jsonPath("$.issues.[0].field").value("wiedervorlage.betreff"))
-						.andExpect(jsonPath("$.issues.[0].messageCode").value(ValidationMessageCodes.FIELD_IS_EMPTY));
+						.andExpect(jsonPath("$.invalidParams.length()").value(1))
+						.andExpect(jsonPath("$.invalidParams[0].name").value("editWiedervorlage.wiedervorlage.betreff"))
+						.andExpect(jsonPath("$.invalidParams[0].reason").value(ValidationMessageCodes.FIELD_IS_EMPTY));
 			}
 
 			@SneakyThrows
@@ -115,7 +115,7 @@ class WiedervorlageCommandITCase {
 				String content = buildContentWithBetreff("a");
 
 				doRequest(content).andExpect(status().isUnprocessableEntity())
-						.andExpect(jsonPath("$.issues.[0].field").value("wiedervorlage.betreff"));
+						.andExpect(jsonPath("$.invalidParams[0].name").value("editWiedervorlage.wiedervorlage.betreff"));
 
 			}
 
@@ -125,7 +125,8 @@ class WiedervorlageCommandITCase {
 			void minMaxParameter() {
 				String content = buildContentWithBetreff("a");
 
-				doRequest(content).andExpect(status().isUnprocessableEntity()).andExpect(jsonPath("$.issues[0].parameters.length()").value(2));
+				doRequest(content).andExpect(status().isUnprocessableEntity())
+						.andExpect(jsonPath("$.invalidParams[0].constraintParameters.length()").value(2));
 			}
 
 			@SneakyThrows
@@ -148,9 +149,9 @@ class WiedervorlageCommandITCase {
 				String content = createEditContent(WiedervorlageTestFactory.createBuilder().frist(LocalDate.parse("2020-01-01")).build());
 
 				doRequest(content).andExpect(status().isUnprocessableEntity())
-						.andExpect(jsonPath("$.issues.length()").value(1))
-						.andExpect(jsonPath("$.issues.[0].field").value("wiedervorlage.frist"))
-						.andExpect(jsonPath("$.issues.[0].messageCode").value(ValidationMessageCodes.FIELD_DATE_PAST));
+						.andExpect(jsonPath("$.invalidParams.length()").value(1))
+						.andExpect(jsonPath("$.invalidParams[0].name").value("editWiedervorlage.wiedervorlage.frist"))
+						.andExpect(jsonPath("$.invalidParams[0].reason").value(ValidationMessageCodes.FIELD_DATE_PAST));
 			}
 
 			@SneakyThrows
@@ -160,9 +161,9 @@ class WiedervorlageCommandITCase {
 				String content = createEditContent(WiedervorlageTestFactory.createBuilder().frist(null).build());
 
 				doRequest(content).andExpect(status().isUnprocessableEntity())
-						.andExpect(jsonPath("$.issues.length()").value(1))
-						.andExpect(jsonPath("$.issues.[0].field").value("wiedervorlage.frist"))
-						.andExpect(jsonPath("$.issues.[0].messageCode").value(ValidationMessageCodes.FIELD_IS_EMPTY));
+						.andExpect(jsonPath("$.invalidParams.length()").value(1))
+						.andExpect(jsonPath("$.invalidParams[0].name").value("editWiedervorlage.wiedervorlage.frist"))
+						.andExpect(jsonPath("$.invalidParams[0].reason").value(ValidationMessageCodes.FIELD_IS_EMPTY));
 			}
 
 			private String createEditContent(Wiedervorlage wiedervorlage) {
@@ -225,9 +226,9 @@ class WiedervorlageCommandITCase {
 				String content = buildContentWithBetreff(null);
 
 				doRequest(content).andExpect(status().isUnprocessableEntity())
-						.andExpect(jsonPath("$.issues.length()").value(1))
-						.andExpect(jsonPath("$.issues.[0].field").value("wiedervorlage.betreff"))
-						.andExpect(jsonPath("$.issues.[0].messageCode").value(ValidationMessageCodes.FIELD_IS_EMPTY));
+						.andExpect(jsonPath("$.invalidParams.length()").value(1))
+						.andExpect(jsonPath("$.invalidParams[0].name").value("createWiedervorlage.wiedervorlage.betreff"))
+						.andExpect(jsonPath("$.invalidParams[0].reason").value(ValidationMessageCodes.FIELD_IS_EMPTY));
 			}
 
 			@SneakyThrows
@@ -237,7 +238,7 @@ class WiedervorlageCommandITCase {
 				String content = buildContentWithBetreff("a");
 
 				doRequest(content).andExpect(status().isUnprocessableEntity())
-						.andExpect(jsonPath("$.issues.[0].field").value("wiedervorlage.betreff"));
+						.andExpect(jsonPath("$.invalidParams[0].name").value("createWiedervorlage.wiedervorlage.betreff"));
 
 			}
 
@@ -247,7 +248,8 @@ class WiedervorlageCommandITCase {
 			void minMaxParameter() {
 				String content = buildContentWithBetreff("a");
 
-				doRequest(content).andExpect(status().isUnprocessableEntity()).andExpect(jsonPath("$.issues[0].parameters.length()").value(2));
+				doRequest(content).andExpect(status().isUnprocessableEntity())
+						.andExpect(jsonPath("$.invalidParams[0].constraintParameters.length()").value(2));
 			}
 
 			@SneakyThrows
@@ -272,9 +274,9 @@ class WiedervorlageCommandITCase {
 						createWithWiedervorlage(WiedervorlageTestFactory.createBuilder().frist(LocalDate.parse("2020-01-01")).build()));
 
 				doRequest(content).andExpect(status().isUnprocessableEntity())
-						.andExpect(jsonPath("$.issues.length()").value(1))
-						.andExpect(jsonPath("$.issues.[0].field").value("wiedervorlage.frist"))
-						.andExpect(jsonPath("$.issues.[0].messageCode").value(ValidationMessageCodes.FIELD_DATE_PAST));
+						.andExpect(jsonPath("$.invalidParams.length()").value(1))
+						.andExpect(jsonPath("$.invalidParams[0].name").value("createWiedervorlage.wiedervorlage.frist"))
+						.andExpect(jsonPath("$.invalidParams[0].reason").value(ValidationMessageCodes.FIELD_DATE_PAST));
 			}
 
 			@SneakyThrows
@@ -285,9 +287,9 @@ class WiedervorlageCommandITCase {
 						createWithWiedervorlage(WiedervorlageTestFactory.createBuilder().frist(null).build()));
 
 				doRequest(content).andExpect(status().isUnprocessableEntity())
-						.andExpect(jsonPath("$.issues.length()").value(1))
-						.andExpect(jsonPath("$.issues.[0].field").value("wiedervorlage.frist"))
-						.andExpect(jsonPath("$.issues.[0].messageCode").value(ValidationMessageCodes.FIELD_IS_EMPTY));
+						.andExpect(jsonPath("$.invalidParams.length()").value(1))
+						.andExpect(jsonPath("$.invalidParams[0].name").value("createWiedervorlage.wiedervorlage.frist"))
+						.andExpect(jsonPath("$.invalidParams[0].reason").value(ValidationMessageCodes.FIELD_IS_EMPTY));
 			}
 
 		}