From bce11d27f06a7d5a1d454b32598e27cfeea5582f Mon Sep 17 00:00:00 2001
From: Jan <j.ackermann91@gmail.com>
Date: Thu, 27 Jul 2023 12:59:38 +0200
Subject: [PATCH] Enable error log for ocs and webdav requests  (#9482)

---
 ...t-error-notifications-include-x-request-id | 11 ++++++
 .../OcNotificationMessage.vue                 | 36 +++++++++----------
 .../InviteCollaboratorForm.vue                |  4 +--
 .../actions/files/useFileActionsRestore.ts    |  5 ++-
 .../src/helpers/resource/actions/transfer.ts  |  3 +-
 .../web-app-files/src/helpers/share/link.ts   | 33 ++++++++++-------
 .../src/helpers/share/triggerShareAction.ts   |  3 +-
 .../composables/download/useDownloadFile.ts   | 22 +++++-------
 packages/web-pkg/src/errors/types.ts          |  8 +++++
 packages/web-pkg/src/services/archiver.ts     |  4 +--
 packages/web-runtime/package.json             |  2 +-
 packages/web-runtime/src/store/app.ts         | 17 +++++++--
 pnpm-lock.yaml                                | 34 +++++++++++++++---
 .../shareWithUsers.feature                    |  4 +--
 .../shareWithUsers.feature                    |  4 +--
 tests/acceptance/pageObjects/webPage.js       |  3 +-
 16 files changed, 127 insertions(+), 66 deletions(-)
 create mode 100644 changelog/enhancement-error-notifications-include-x-request-id

diff --git a/changelog/enhancement-error-notifications-include-x-request-id b/changelog/enhancement-error-notifications-include-x-request-id
new file mode 100644
index 00000000000..bc2ea93c9a3
--- /dev/null
+++ b/changelog/enhancement-error-notifications-include-x-request-id
@@ -0,0 +1,11 @@
+Enhancement: Error notifications include x-request-id
+
+We've added a details box for the notifications, that pop up if an operation (e.g upload, download, add a share) fails.
+This box contains the x-request-id and may help to debug the error on the server side.
+
+https://github.com/owncloud/web/pull/9482
+https://github.com/owncloud/web/pull/9474
+https://github.com/owncloud/web/pull/9466
+https://github.com/owncloud/web/pull/9448
+https://github.com/owncloud/web/pull/9426
+https://github.com/owncloud/web/issues/9449
diff --git a/packages/design-system/src/components/OcNotificationMessage/OcNotificationMessage.vue b/packages/design-system/src/components/OcNotificationMessage/OcNotificationMessage.vue
index fe9586da950..15ec854d055 100644
--- a/packages/design-system/src/components/OcNotificationMessage/OcNotificationMessage.vue
+++ b/packages/design-system/src/components/OcNotificationMessage/OcNotificationMessage.vue
@@ -15,26 +15,24 @@
           ><oc-icon name="close"
         /></oc-button>
       </div>
-      <div class="oc-width-1-1">
-        <div class="oc-flex oc-flex-between oc-width-1-1 oc-mt-s">
-          <span
-            v-if="message"
-            class="oc-notification-message-content oc-text-muted oc-mr-s"
-            v-text="message"
-          />
-          <oc-button
-            v-if="errorLogContent"
-            class="oc-notification-message-error-log-toggle-button"
-            gap-size="none"
-            appearance="raw"
-            @click="showErrorLog = !showErrorLog"
-          >
-            <span v-text="$gettext('Details')"></span>
-            <oc-icon :name="showErrorLog ? 'arrow-up-s' : 'arrow-down-s'" />
-          </oc-button>
-        </div>
-        <oc-error-log v-if="showErrorLog" class="oc-mt-m" :content="errorLogContent" />
+      <div v-if="message || errorLogContent" class="oc-flex oc-flex-between oc-width-1-1 oc-mt-s">
+        <span
+          v-if="message"
+          class="oc-notification-message-content oc-text-muted oc-mr-s"
+          v-text="message"
+        />
+        <oc-button
+          v-if="errorLogContent"
+          class="oc-notification-message-error-log-toggle-button"
+          gap-size="none"
+          appearance="raw"
+          @click="showErrorLog = !showErrorLog"
+        >
+          <span v-text="$gettext('Details')"></span>
+          <oc-icon :name="showErrorLog ? 'arrow-up-s' : 'arrow-down-s'" />
+        </oc-button>
       </div>
+      <oc-error-log v-if="showErrorLog" class="oc-mt-m" :content="errorLogContent" />
     </div>
   </div>
 </template>
diff --git a/packages/web-app-files/src/components/SideBar/Shares/Collaborators/InviteCollaborator/InviteCollaboratorForm.vue b/packages/web-app-files/src/components/SideBar/Shares/Collaborators/InviteCollaborator/InviteCollaboratorForm.vue
index 769c8b54c5c..429fd5b4450 100644
--- a/packages/web-app-files/src/components/SideBar/Shares/Collaborators/InviteCollaborator/InviteCollaboratorForm.vue
+++ b/packages/web-app-files/src/components/SideBar/Shares/Collaborators/InviteCollaborator/InviteCollaboratorForm.vue
@@ -352,10 +352,10 @@ export default defineComponent({
       }
       errors.forEach((e) => {
         this.showErrorMessage({
-          title: this.$gettext('Failed to add share for %{displayName}', {
+          title: this.$gettext('Failed to add share for "%{displayName}"', {
             displayName: e.displayName
           }),
-          error: e
+          error: e.error
         })
       })
 
diff --git a/packages/web-app-files/src/composables/actions/files/useFileActionsRestore.ts b/packages/web-app-files/src/composables/actions/files/useFileActionsRestore.ts
index be3c73a0b22..59e2e52a6c3 100644
--- a/packages/web-app-files/src/composables/actions/files/useFileActionsRestore.ts
+++ b/packages/web-app-files/src/composables/actions/files/useFileActionsRestore.ts
@@ -158,6 +158,7 @@ export const useFileActionsRestore = ({ store }: { store?: Store<any> } = {}) =>
   ) => {
     const restoredResources = []
     const failedResources = []
+    const errors = []
 
     let createdFolderPaths = []
     for (const [i, resource] of resources.entries()) {
@@ -174,6 +175,7 @@ export const useFileActionsRestore = ({ store }: { store?: Store<any> } = {}) =>
         restoredResources.push(resource)
       } catch (e) {
         console.error(e)
+        errors.push(e)
         failedResources.push(resource)
       } finally {
         setProgress({ total: resources.length, current: i + 1 })
@@ -209,7 +211,8 @@ export const useFileActionsRestore = ({ store }: { store?: Store<any> } = {}) =>
         translateParams.resourceCount = failedResources.length
       }
       store.dispatch('showErrorMessage', {
-        title: $gettextInterpolate(translated, translateParams, true)
+        title: $gettextInterpolate(translated, translateParams, true),
+        errors
       })
     }
 
diff --git a/packages/web-app-files/src/helpers/resource/actions/transfer.ts b/packages/web-app-files/src/helpers/resource/actions/transfer.ts
index 6747ff87ca2..62785c0da0d 100644
--- a/packages/web-app-files/src/helpers/resource/actions/transfer.ts
+++ b/packages/web-app-files/src/helpers/resource/actions/transfer.ts
@@ -99,7 +99,8 @@ export class ResourceTransfer extends ConflictDialog {
       )
     }
     this.showErrorMessage({
-      title
+      title,
+      errors
     })
   }
 
diff --git a/packages/web-app-files/src/helpers/share/link.ts b/packages/web-app-files/src/helpers/share/link.ts
index 69705cf04d1..6f912eca3f9 100644
--- a/packages/web-app-files/src/helpers/share/link.ts
+++ b/packages/web-app-files/src/helpers/share/link.ts
@@ -68,19 +68,26 @@ export const createQuicklink = async (args: CreateQuicklink): Promise<Share> =>
 
   params.spaceRef = resource.fileId || resource.id
 
-  const link = await store.dispatch('Files/addLink', {
-    path: resource.path,
-    client: clientService.owncloudSdk,
-    params,
-    storageId: resource.fileId || resource.id
-  })
+  try {
+    const link = await store.dispatch('Files/addLink', {
+      path: resource.path,
+      client: clientService.owncloudSdk,
+      params,
+      storageId: resource.fileId || resource.id
+    })
+    const { copy } = useClipboard({ legacy: true })
+    copy(link.url)
 
-  const { copy } = useClipboard({ legacy: true })
-  copy(link.url)
+    await store.dispatch('showMessage', {
+      title: $gettext('The link has been copied to your clipboard.')
+    })
 
-  await store.dispatch('showMessage', {
-    title: $gettext('The link has been copied to your clipboard.')
-  })
-
-  return link
+    return link
+  } catch (e) {
+    console.error(e)
+    await store.dispatch('showErrorMessage', {
+      title: $gettext('Copy link failed'),
+      error: e
+    })
+  }
 }
diff --git a/packages/web-app-files/src/helpers/share/triggerShareAction.ts b/packages/web-app-files/src/helpers/share/triggerShareAction.ts
index 47f706df7c9..be537a83e28 100644
--- a/packages/web-app-files/src/helpers/share/triggerShareAction.ts
+++ b/packages/web-app-files/src/helpers/share/triggerShareAction.ts
@@ -1,5 +1,6 @@
 import { aggregateResourceShares } from '../resources'
 import { ShareStatus } from 'web-client/src/helpers/share/status'
+import { HttpError } from 'web-pkg/src/errors'
 
 export async function triggerShareAction(resource, status, hasReSharing, hasShareJail, $client) {
   const method = _getRequestMethod(status)
@@ -16,7 +17,7 @@ export async function triggerShareAction(resource, status, hasReSharing, hasShar
 
   // exit on failure
   if (response.status !== 200) {
-    throw new Error(response.statusText)
+    throw new HttpError(response.statusText, response)
   }
 
   // get updated share from response and transform & return it
diff --git a/packages/web-pkg/src/composables/download/useDownloadFile.ts b/packages/web-pkg/src/composables/download/useDownloadFile.ts
index 05efa51ac89..134abce8716 100644
--- a/packages/web-pkg/src/composables/download/useDownloadFile.ts
+++ b/packages/web-pkg/src/composables/download/useDownloadFile.ts
@@ -2,7 +2,6 @@ import { unref } from 'vue'
 import { usePublicLinkContext } from '../authContext'
 import { useClientService } from '../clientService'
 import { useStore } from '../store'
-import { v4 as uuidV4 } from 'uuid'
 import { triggerDownloadWithFilename } from 'web-pkg/src/helpers'
 import { useGettext } from 'vue3-gettext'
 import { useCapabilityCoreSupportUrlSigning } from '../capability'
@@ -19,8 +18,7 @@ export const useDownloadFile = () => {
     const isUserContext = store.getters['runtime/auth/isUserContextReady']
 
     // construct the url and headers
-    let url = null
-    let headers: Record<string, string> = { 'X-Request-ID': uuidV4() }
+    let url
     if (unref(isPublicLinkContext)) {
       url = file.downloadURL
     } else {
@@ -29,17 +27,13 @@ export const useDownloadFile = () => {
       } else {
         url = client.fileVersions.getFileVersionUrl(file.fileId, version)
       }
-      const accessToken = store.getters['runtime/auth/accessToken']
-      headers = { Authorization: 'Bearer ' + accessToken }
     }
 
     // download with signing enabled
     if (isUserContext && unref(isUrlSigningEnabled)) {
+      const httpClient = clientService.httpAuthenticated
       try {
-        const response = await fetch(url, {
-          method: 'HEAD',
-          headers
-        })
+        const response = await httpClient.head(url)
         if (response.status === 200) {
           const signedUrl = await client.signUrl(url)
           triggerDownloadWithFilename(signedUrl, file.name)
@@ -47,12 +41,12 @@ export const useDownloadFile = () => {
         }
       } catch (e) {
         console.error(e)
+        store.dispatch('showErrorMessage', {
+          title: $gettext('Download failed'),
+          desc: $gettext('File could not be located'),
+          error: e
+        })
       }
-      store.dispatch('showErrorMessage', {
-        title: $gettext('Download failed'),
-        desc: $gettext('File could not be located'),
-        status: 'danger'
-      })
       return
     }
 
diff --git a/packages/web-pkg/src/errors/types.ts b/packages/web-pkg/src/errors/types.ts
index 9e9571a3690..92b34bb255f 100644
--- a/packages/web-pkg/src/errors/types.ts
+++ b/packages/web-pkg/src/errors/types.ts
@@ -18,3 +18,11 @@ export class RuntimeError extends Error {
 export class ApiError extends RuntimeError {
   name = 'ApiError'
 }
+
+export class HttpError extends Error {
+  public response: any
+  constructor(message, response) {
+    super(message)
+    this.response = response
+  }
+}
diff --git a/packages/web-pkg/src/services/archiver.ts b/packages/web-pkg/src/services/archiver.ts
index 62c43fa10aa..8e85d25d404 100644
--- a/packages/web-pkg/src/services/archiver.ts
+++ b/packages/web-pkg/src/services/archiver.ts
@@ -2,7 +2,7 @@
 import major from 'semver/functions/major'
 import rcompare from 'semver/functions/rcompare'
 
-import { RuntimeError } from 'web-pkg/src/errors'
+import { HttpError, RuntimeError } from 'web-pkg/src/errors'
 import { ClientService } from 'web-pkg/src/services'
 import { urlJoin } from 'web-client/src/utils'
 import { configurationManager } from 'web-pkg/src/configuration'
@@ -99,7 +99,7 @@ export class ArchiverService {
       triggerDownloadWithFilename(objectUrl, fileName)
       return url
     } catch (e) {
-      throw new RuntimeError('archive could not be fetched')
+      throw new HttpError('archive could not be fetched', e.response)
     }
   }
 
diff --git a/packages/web-runtime/package.json b/packages/web-runtime/package.json
index 58d2c068a71..ec75cfcb42d 100644
--- a/packages/web-runtime/package.json
+++ b/packages/web-runtime/package.json
@@ -27,7 +27,7 @@
     "luxon": "^2.4.0",
     "marked": "^4.0.12",
     "oidc-client-ts": "^2.1.0",
-    "owncloud-sdk": "~3.1.0-alpha.4",
+    "owncloud-sdk": "~3.1.0-alpha.6",
     "p-queue": "^6.6.2",
     "pinia": "^2.1.3",
     "portal-vue": "3.0.0",
diff --git a/packages/web-runtime/src/store/app.ts b/packages/web-runtime/src/store/app.ts
index 16096a181d3..7d211a4f90d 100644
--- a/packages/web-runtime/src/store/app.ts
+++ b/packages/web-runtime/src/store/app.ts
@@ -1,5 +1,3 @@
-import { AxiosError } from 'axios'
-
 const state = {
   messages: [],
   quickActions: {}
@@ -7,7 +5,20 @@ const state = {
 
 const actions = {
   showErrorMessage({ commit }, message) {
-    const getXRequestID = (error: AxiosError): string | null => {
+    const getXRequestID = (error: any): string | null => {
+      /**
+       * x-request-id response headers might be very nested in ownCloud SDK,
+       * only remove records if you are sure they aren't valid anymore
+       */
+      if (error.response?.res?.res?.headers?.['x-request-id']) {
+        return error.response.res.res.headers['x-request-id']
+      }
+      if (error.response?.headers?.map?.['x-request-id']) {
+        return error.response.headers.map['x-request-id']
+      }
+      if (error.response?.res?.headers?.['x-request-id']) {
+        return error.response.res.headers['x-request-id']
+      }
       if (error.response?.headers?.['x-request-id']) {
         return error.response.headers['x-request-id']
       }
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 9be646d4623..66d6e8e8789 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -1025,8 +1025,8 @@ importers:
         specifier: ^2.1.0
         version: 2.1.0
       owncloud-sdk:
-        specifier: ~3.1.0-alpha.4
-        version: 3.1.0-alpha.4(axios@1.4.0)(cross-fetch@3.1.4)(promise@8.1.0)(qs@6.10.3)(utf8@3.0.0)(uuid@9.0.0)(webdav@4.10.0)(xml-js@1.6.11)
+        specifier: ~3.1.0-alpha.6
+        version: 3.1.0-alpha.6(axios@1.4.0)(cross-fetch@3.1.4)(promise@8.1.0)(qs@6.10.3)(utf8@3.0.0)(uuid@9.0.0)(webdav@4.10.0)(xml-js@1.6.11)
       p-queue:
         specifier: ^6.6.2
         version: 6.6.2
@@ -7381,6 +7381,7 @@ packages:
 
   /anymatch@2.0.0(supports-color@6.1.0):
     resolution: {integrity: sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==}
+    requiresBuild: true
     dependencies:
       micromatch: 3.1.10(supports-color@6.1.0)
       normalize-path: 2.1.1
@@ -7571,6 +7572,7 @@ packages:
 
   /assert-never@1.2.1:
     resolution: {integrity: sha512-TaTivMB6pYI1kXwrFlEhLeGfOqoDNdTxjCdwRfFFkEA30Eu+k48W34nlok2EYWJfFFzqaEmichdNM7th6M5HNw==}
+    requiresBuild: true
 
   /assert-plus@1.0.0:
     resolution: {integrity: sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==}
@@ -7639,6 +7641,7 @@ packages:
 
   /async-each@1.0.3:
     resolution: {integrity: sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==}
+    requiresBuild: true
     dev: true
 
   /async-limiter@1.0.1:
@@ -8044,6 +8047,7 @@ packages:
   /babel-walk@3.0.0-canary-5:
     resolution: {integrity: sha512-GAwkz0AihzY5bkwIY5QDR+LvsRQgB/B+1foMPvi0FZPMl5fjD7ICiznUiBdLYMH1QYe6vqu4gWYytZOccLouFw==}
     engines: {node: '>= 10.0.0'}
+    requiresBuild: true
     dependencies:
       '@babel/types': 7.21.5
 
@@ -8107,6 +8111,7 @@ packages:
   /binary-extensions@1.13.1:
     resolution: {integrity: sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==}
     engines: {node: '>=0.10.0'}
+    requiresBuild: true
     dev: true
 
   /binary-extensions@2.2.0:
@@ -8636,6 +8641,7 @@ packages:
 
   /character-parser@2.2.0:
     resolution: {integrity: sha512-+UqJQjFEFaTAs3bNsF2j2kEN1baG/zghZbdqoYEDxGZtJo9LBzl1A+m0D4n3qKx8N2FNv8/Xp6yV9mQmBuptaw==}
+    requiresBuild: true
     dependencies:
       is-regex: 1.1.4
 
@@ -9333,6 +9339,7 @@ packages:
 
   /constantinople@4.0.1:
     resolution: {integrity: sha512-vCrqcSIq4//Gx74TXXCGnHpulY1dskqLTFGDmhrGxzeXL8lF8kvXv6mpNWlJj1uD4DW23D4ljAqbY4RRaaUZIw==}
+    requiresBuild: true
     dependencies:
       '@babel/parser': 7.21.8
       '@babel/types': 7.21.5
@@ -10473,6 +10480,7 @@ packages:
 
   /doctypes@1.1.0:
     resolution: {integrity: sha512-LLBi6pEqS6Do3EKQ3J0NqHWV5hhb78Pi8vvESYwyOy2c31ZEZVdtitdzsQsKb7878PEERhzUk0ftqGhG6Mz+pQ==}
+    requiresBuild: true
 
   /dom-serializer@1.3.2:
     resolution: {integrity: sha512-5c54Bk5Dw4qAxNOI1pFEizPSjVsx5+bpJKmL2kPn8JhBUq2q09tTCa3mjijun2NfK78NMouDYNMBkOrPZiS+ig==}
@@ -12919,6 +12927,7 @@ packages:
   /is-binary-path@1.0.1:
     resolution: {integrity: sha512-9fRVlXc0uCxEDj1nQzaWONSpbTfx0FmJfzHF7pwlI8DkWGoHBBea4Pg5Ky0ojwwxQmnSifgbKkI06Qv0Ljgj+Q==}
     engines: {node: '>=0.10.0'}
+    requiresBuild: true
     dependencies:
       binary-extensions: 1.13.1
     dev: true
@@ -13015,6 +13024,7 @@ packages:
 
   /is-expression@4.0.0:
     resolution: {integrity: sha512-zMIXX63sxzG3XrkHkrAPvm/OVZVSCPNkwMHU8oTX7/U3AL78I0QXCEICXUM13BIa8TYGZ68PiTKfQz3yaTNr4A==}
+    requiresBuild: true
     dependencies:
       acorn: 7.4.1
       object-assign: 4.1.1
@@ -13055,6 +13065,7 @@ packages:
   /is-glob@3.1.0:
     resolution: {integrity: sha512-UFpDDrPgM6qpnFNI+rh/p3bUaq9hKLZN8bMUWzxmcnZVS3omf4IPK+BrewlnWjO1WmUsMYuSjKh4UJuV4+Lqmw==}
     engines: {node: '>=0.10.0'}
+    requiresBuild: true
     dependencies:
       is-extglob: 2.1.1
     dev: true
@@ -13159,6 +13170,7 @@ packages:
 
   /is-promise@2.2.2:
     resolution: {integrity: sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==}
+    requiresBuild: true
 
   /is-regex@1.1.4:
     resolution: {integrity: sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==}
@@ -14003,6 +14015,7 @@ packages:
 
   /js-stringify@1.0.2:
     resolution: {integrity: sha512-rtS5ATOo2Q5k1G+DADISilDA6lv79zIiwFd6CcjuIxGKLFm5C+RLImRscVap9k55i+MOZwgliw+NejvkLuGD5g==}
+    requiresBuild: true
 
   /js-tokens@4.0.0:
     resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
@@ -14217,6 +14230,7 @@ packages:
 
   /jstransformer@1.0.0:
     resolution: {integrity: sha512-C9YK3Rf8q6VAPDCCU9fnqo3mAfOH6vUGnMcP4AQAYIEpWtfGLpwOTmZ+igtdK5y+VvI2n3CyYSzy4Qh34eq24A==}
+    requiresBuild: true
     dependencies:
       is-promise: 2.2.2
       promise: 7.3.1
@@ -15567,6 +15581,7 @@ packages:
   /normalize-path@2.1.1:
     resolution: {integrity: sha512-3pKJwH184Xo/lnH6oyP1q2pMd7HcypqqmRs91/6/i2CGtWwIKGCkOOMTm/zXbgTEWHw1uNpNi/igc3ePOYHb6w==}
     engines: {node: '>=0.10.0'}
+    requiresBuild: true
     dependencies:
       remove-trailing-separator: 1.1.0
     dev: true
@@ -15940,8 +15955,8 @@ packages:
     engines: {node: '>=0.10.0'}
     dev: true
 
-  /owncloud-sdk@3.1.0-alpha.4(axios@1.4.0)(cross-fetch@3.1.4)(promise@8.1.0)(qs@6.10.3)(utf8@3.0.0)(uuid@9.0.0)(webdav@4.10.0)(xml-js@1.6.11):
-    resolution: {integrity: sha512-Z+ZKPhccB+BrPKqT5Lv8jwTl3zBtw8POgytPi5jByNQpPoU1JuQ9H32ysHa3yFU/rhIuYWWDBSHPlvw+nyIUlA==}
+  /owncloud-sdk@3.1.0-alpha.6(axios@1.4.0)(cross-fetch@3.1.4)(promise@8.1.0)(qs@6.10.3)(utf8@3.0.0)(uuid@9.0.0)(webdav@4.10.0)(xml-js@1.6.11):
+    resolution: {integrity: sha512-U079L2Bjfx9hi3d1+hapR8Umyoj/hY8QQhqiy+/J7shwPKHFRdzZoyJkTtL+zOwOjqFfBIOZYEvOWPY5+5k3HA==}
     peerDependencies:
       axios: ^0.27.2
       cross-fetch: ^3.0.6
@@ -16211,6 +16226,7 @@ packages:
 
   /path-dirname@1.0.2:
     resolution: {integrity: sha512-ALzNPpyNq9AqXMBjeymIjFDAkAFH06mHJH/cSBHAgU0s4vfpBn6b2nf8tiRLvagKD8RbTpq2FKTBg7cl9l3c7Q==}
+    requiresBuild: true
     dev: true
 
   /path-exists@3.0.0:
@@ -17091,6 +17107,7 @@ packages:
 
   /promise@7.3.1:
     resolution: {integrity: sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==}
+    requiresBuild: true
     dependencies:
       asap: 2.0.6
 
@@ -17179,6 +17196,7 @@ packages:
 
   /pug-attrs@3.0.0:
     resolution: {integrity: sha512-azINV9dUtzPMFQktvTXciNAfAuVh/L/JCl0vtPCwvOA21uZrC08K/UnmrL+SXGEVc1FwzjW62+xw5S/uaLj6cA==}
+    requiresBuild: true
     dependencies:
       constantinople: 4.0.1
       js-stringify: 1.0.2
@@ -17198,6 +17216,7 @@ packages:
 
   /pug-error@2.0.0:
     resolution: {integrity: sha512-sjiUsi9M4RAGHktC1drQfCr5C5eriu24Lfbt4s+7SykztEOwVZtbFk1RRq0tzLxcMxMYTBR+zMQaG07J/btayQ==}
+    requiresBuild: true
 
   /pug-filters@4.0.0:
     resolution: {integrity: sha512-yeNFtq5Yxmfz0f9z2rMXGw/8/4i1cCFecw/Q7+D0V2DdtII5UvqE12VaZ2AY7ri6o5RNXiweGH79OCq+2RQU4A==}
@@ -17243,6 +17262,7 @@ packages:
 
   /pug-walk@2.0.0:
     resolution: {integrity: sha512-yYELe9Q5q9IQhuvqsZNwA5hfPkMJ8u92bQLIMcsMxf/VADjNtEYptU+inlufAFYcWdHlwNfZOEnOOQrZrcyJCQ==}
+    requiresBuild: true
 
   /pug@3.0.2:
     resolution: {integrity: sha512-bp0I/hiK1D1vChHh6EfDxtndHji55XP/ZJKwsRqrz6lRia6ZC2OZbdAymlxdVFwd1L70ebrVJw4/eZ79skrIaw==}
@@ -17755,6 +17775,7 @@ packages:
   /readdirp@2.2.1(supports-color@6.1.0):
     resolution: {integrity: sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==}
     engines: {node: '>=0.10'}
+    requiresBuild: true
     dependencies:
       graceful-fs: 4.2.10
       micromatch: 3.1.10(supports-color@6.1.0)
@@ -17999,6 +18020,7 @@ packages:
 
   /remove-trailing-separator@1.1.0:
     resolution: {integrity: sha512-/hS+Y0u3aOfIETiaiirUFwDBDzmXPvO+jAfKTitUngIPzdKc6Z0LoFjM/CK5PL4C+eKwHohlHAb6H0VFfmmUsw==}
+    requiresBuild: true
     dev: true
 
   /repeat-element@1.1.4:
@@ -19672,6 +19694,7 @@ packages:
 
   /token-stream@1.0.0:
     resolution: {integrity: sha512-VSsyNPPW74RpHwR8Fc21uubwHY7wMDeJLys2IX5zJNih+OnAnaifKHo+1LHT7DAdloQ7apeaaWg8l7qnf/TnEg==}
+    requiresBuild: true
 
   /totalist@1.1.0:
     resolution: {integrity: sha512-gduQwd1rOdDMGxFG1gEvhV88Oirdo2p+KjoYFU7k2g+i7n6AFFbDQ5kMPUsW0pNbfQsB/cwXvT1i4Bue0s9g5g==}
@@ -20126,6 +20149,7 @@ packages:
   /upath@1.2.0:
     resolution: {integrity: sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==}
     engines: {node: '>=4'}
+    requiresBuild: true
     dev: true
 
   /update-browserslist-db@1.0.10(browserslist@4.21.4):
@@ -20451,6 +20475,7 @@ packages:
   /void-elements@3.1.0:
     resolution: {integrity: sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==}
     engines: {node: '>=0.10.0'}
+    requiresBuild: true
 
   /vue-concurrency@4.0.1(vue@3.3.4):
     resolution: {integrity: sha512-gzZjC8o9EE1/d7OEndI0C8lO09nkLSbviT94/gQR372iLVbYKZiGto87upjV9TAHodTfzbBgjyQXH53AVI5ugA==}
@@ -21249,6 +21274,7 @@ packages:
   /with@7.0.2:
     resolution: {integrity: sha512-RNGKj82nUPg3g5ygxkQl0R937xLyho1J24ItRCBTr/m1YnZkzJy1hUiHUJrc/VlsDQzsCnInEGSg3bci0Lmd4w==}
     engines: {node: '>= 10.0.0'}
+    requiresBuild: true
     dependencies:
       '@babel/parser': 7.21.8
       '@babel/types': 7.21.5
diff --git a/tests/acceptance/features/webUISharingInternalUsers/shareWithUsers.feature b/tests/acceptance/features/webUISharingInternalUsers/shareWithUsers.feature
index 00d10eefe09..4177833c9d5 100644
--- a/tests/acceptance/features/webUISharingInternalUsers/shareWithUsers.feature
+++ b/tests/acceptance/features/webUISharingInternalUsers/shareWithUsers.feature
@@ -162,12 +162,12 @@ Feature: Sharing files and folders with internal users
       | lorem.txt     |
       | simple-folder |
     When the user shares file "lorem.txt" with user "Brian Murphy" as "Editor" using the webUI
-    Then the "error" message with header 'Failed to add share for Brian Murphy' should be displayed on the webUI
+    Then the "error" message with header 'Failed to add share for "Brian Murphy"' should be displayed on the webUI
     And the user clears all error message from the webUI
     And user "Brian Murphy" should not be listed in the collaborators list on the webUI
     When the user clears all error message from the webUI
     And the user shares folder "simple-folder" with user "Brian Murphy" as "Editor" using the webUI
-    Then the "error" message with header 'Failed to add share for Brian Murphy' should be displayed on the webUI
+    Then the "error" message with header 'Failed to add share for "Brian Murphy"' should be displayed on the webUI
     And the user clears all error message from the webUI
     And user "Brian Murphy" should not be listed in the collaborators list on the webUI
     When the user reloads the current page of the webUI
diff --git a/tests/acceptance/features/webUISharingInternalUsersToRoot/shareWithUsers.feature b/tests/acceptance/features/webUISharingInternalUsersToRoot/shareWithUsers.feature
index 5a168a5a140..26d71546c11 100644
--- a/tests/acceptance/features/webUISharingInternalUsersToRoot/shareWithUsers.feature
+++ b/tests/acceptance/features/webUISharingInternalUsersToRoot/shareWithUsers.feature
@@ -159,12 +159,12 @@ Feature: Sharing files and folders with internal users
       | lorem.txt     |
       | simple-folder |
     When the user shares file "lorem.txt" with user "Brian Murphy" as "Editor" using the webUI
-    Then the "error" message with header 'Failed to add share for Brian Murphy' should be displayed on the webUI
+    Then the "error" message with header 'Failed to add share for "Brian Murphy"' should be displayed on the webUI
     And the user clears all error message from the webUI
     And user "UserTwo" should not be listed in the collaborators list on the webUI
     When the user clears all error message from the webUI
     And the user shares folder "simple-folder" with user "Brian Murphy" as "Editor" using the webUI
-    Then the "error" message with header 'Failed to add share for Brian Murphy' should be displayed on the webUI
+    Then the "error" message with header 'Failed to add share for "Brian Murphy"' should be displayed on the webUI
     And the user clears all error message from the webUI
     And user "UserTwo" should not be listed in the collaborators list on the webUI
     When the user reloads the current page of the webUI
diff --git a/tests/acceptance/pageObjects/webPage.js b/tests/acceptance/pageObjects/webPage.js
index d5574daf2bc..6e14904b5e5 100644
--- a/tests/acceptance/pageObjects/webPage.js
+++ b/tests/acceptance/pageObjects/webPage.js
@@ -231,7 +231,8 @@ module.exports = {
       locateStrategy: 'xpath'
     },
     errorMessages: {
-      selector: '//*[contains(@class, "oc-notification-message-danger")]',
+      selector:
+        '//div[contains(@class, "oc-notification-message-danger")]//div[@class="oc-notification-message-title"]',
       locateStrategy: 'xpath'
     },
     clearErrorMessage: {