diff --git a/dbrepo-ui/bun.lockb b/dbrepo-ui/bun.lockb
index b82e45d505fdc0e1f41e246f7d1caefe3e23007c..45a8c51c621dab127458d68a4493b23d2df9f88d 100755
Binary files a/dbrepo-ui/bun.lockb and b/dbrepo-ui/bun.lockb differ
diff --git a/dbrepo-ui/composables/database-service.ts b/dbrepo-ui/composables/database-service.ts
index b96d75ab80e880f52d416fef382f9d22de444502..7956f7b4dff6cb748733fd381275dd6d0622b60c 100644
--- a/dbrepo-ui/composables/database-service.ts
+++ b/dbrepo-ui/composables/database-service.ts
@@ -83,7 +83,7 @@ export const useDatabaseService = (): any => {
     });
   }
 
-  async function findOne(id: number): Promise<DatabaseDto | null> {
+  async function findOne(id: number, rawError: boolean = false): Promise<DatabaseDto | null> {
     const axios = useAxiosInstance();
     console.debug('find database with id', id);
     return new Promise((resolve, reject) => {
@@ -94,6 +94,9 @@ export const useDatabaseService = (): any => {
         })
         .catch((error) => {
           console.error('Failed to find database', error);
+          if (rawError) {
+            reject(error)
+          }
           reject(axiosErrorToApiError(error));
         });
     });
diff --git a/dbrepo-ui/composables/table-service.ts b/dbrepo-ui/composables/table-service.ts
index 4abaebec937ecdfc2f965a8184b2982ef776ddce..ca757c7451d70c4bd1fffc36b72c6a23d7fdde58 100644
--- a/dbrepo-ui/composables/table-service.ts
+++ b/dbrepo-ui/composables/table-service.ts
@@ -29,7 +29,7 @@ export const useTableService = (): any => {
           resolve(response.data)
         })
         .catch((error) => {
-          console.error('Failed to find table')
+          console.error('Failed to find table', error)
           reject(axiosErrorToApiError(error))
         })
     })
diff --git a/dbrepo-ui/layouts/default.vue b/dbrepo-ui/layouts/default.vue
index b7baeb7043f333d6e9f6b53bfa6aec20228ef67c..2311be0e05324cfe47896afcbf31137f2cfdc5ea 100644
--- a/dbrepo-ui/layouts/default.vue
+++ b/dbrepo-ui/layouts/default.vue
@@ -150,32 +150,47 @@
     <v-main>
       <v-container>
         <slot />
+        <JumboBox
+          v-if="error"
+          :title="$t(errorCodeKey(error).title, { resource })"
+          :subtitle="$t(errorCodeKey(error).subtitle)"
+          :text="$t(errorCodeKey(error).text, { resource })" />
       </v-container>
     </v-main>
   </v-app>
 </template>
 
 <script setup>
-const config = useRuntimeConfig()
+import { ref } from 'vue'
+
+const runtimeConfig = useRuntimeConfig()
+const config = ref(runtimeConfig)
 useServerHead({
-  title: config.public.title,
+  title: runtimeConfig.public.title,
   meta: [
-    {'ref': 'icon', type: 'image/x-icon', href: config.public.icon},
-    {'http-equiv': 'Content-Security-Policy', content: 'upgrade-insecure-requests'}
+    { 'ref': 'icon', type: 'image/x-icon', href: runtimeConfig.public.icon },
+    { 'http-equiv': 'Content-Security-Policy', content: 'upgrade-insecure-requests' }
   ]
 })
 </script>
 <script>
+import JumboBox from '@/components/JumboBox.vue'
 import { useUserStore } from '@/stores/user'
 import { useCacheStore } from '@/stores/cache'
+import { errorCodeKey, makeError } from '@/utils'
 
 export default {
+  components: {
+    JumboBox
+  },
   data () {
     return {
       drawer: false,
       model: null,
       query: null,
       loading: true,
+      databaseError: null,
+      accessError: null,
       searchResults: [],
       databases: [],
       loadingUser: true,
@@ -199,12 +214,36 @@ export default {
     messages () {
       return this.cacheStore.getMessages
     },
+    access () {
+      return this.userStore.getAccess
+    },
     table () {
       return this.cacheStore.getTable
     },
+    view () {
+      return this.cacheStore.getView
+    },
+    subset () {
+      return this.cacheStore.getSubset
+    },
     database () {
       return this.cacheStore.getDatabase
     },
+    resource () {
+      if (!this.$route.params.database_id) {
+        return null
+      }
+      if (this.$route.params.table_id) {
+        return 'table'
+      }
+      if (this.$route.params.view_id) {
+        return 'view'
+      }
+      if (this.$route.params.subset_id) {
+        return 'subset'
+      }
+      return 'database'
+    },
     roles () {
       return this.userStore.getRoles
     },
@@ -220,6 +259,27 @@ export default {
     commitShort () {
       return this.$config.public.commit.substr(0, 8)
     },
+    error () {
+      if (this.databaseError) {
+        return this.databaseError
+      }
+      if (this.accessError) {
+        return this.accessError
+      }
+      if (!this.user) {
+        return null
+      }
+      if (this.table && !this.table.is_public && !this.table.is_schema_public && !this.table.owner.id !== this.user.id) {
+        return makeError(403, null, null)
+      }
+      if (this.view && !this.view.is_public && !this.view.is_schema_public && !this.view.owner.id !== this.user.id) {
+        return makeError(403, null, null)
+      }
+      if (this.subset && !this.subset.is_public && !this.subset.is_schema_public && !this.subset.owner.id !== this.user.id) {
+        return makeError(403, null, null)
+      }
+      return null
+    },
     canListOntologies () {
       if (!this.roles) {
         return false
@@ -243,25 +303,42 @@ export default {
   watch: {
     '$route.params': {
       handler (newObj, oldObj) {
-        if (!newObj.database_id || import.meta.server) {
+        if (!newObj.database_id) {
+          this.databaseError = null
+          this.accessError = null
+          this.cacheStore.setTable(null)
+          this.cacheStore.setView(null)
+          this.cacheStore.setSubset(null)
+          return
+        }
+        if (import.meta.server) {
           return
         }
         /* load database and optional access */
         this.cacheStore.setRouteDatabase(newObj.database_id)
+          .catch((error) => {
+            this.databaseError = error
+          })
         if (this.user) {
           this.userStore.setRouteAccess(newObj.database_id)
         }
         /* load table */
         if (newObj.table_id) {
           this.cacheStore.setRouteTable(newObj.database_id, newObj.table_id)
+        } else {
+          this.cacheStore.setTable(null)
         }
         /* load view */
         if (newObj.view_id) {
           this.cacheStore.setRouteView(newObj.database_id, newObj.view_id)
+        } else {
+          this.cacheStore.setView(null)
         }
         /* load subset */
         if (newObj.subset_id) {
           this.cacheStore.setRouteSubset(newObj.database_id, newObj.subset_id)
+        } else {
+          this.cacheStore.setSubset(null)
         }
       },
       deep: true,
@@ -280,6 +357,7 @@ export default {
     this.cacheStore.reloadMessages()
   },
   methods: {
+    errorCodeKey,
     login () {
       const redirect = ![undefined, '/', '/login'].includes(this.$router.currentRoute.path)
       this.$router.push({ path: '/login', query: redirect ? { redirect: this.$router.currentRoute.path } : {} })
diff --git a/dbrepo-ui/nuxt.config.ts b/dbrepo-ui/nuxt.config.ts
index b5758d06f5efdf5585e1ff1fc12695ac12c86592..4bce6ec5c5b3dc7f025734d9bf15d8e914123f79 100644
--- a/dbrepo-ui/nuxt.config.ts
+++ b/dbrepo-ui/nuxt.config.ts
@@ -4,18 +4,18 @@ import vuetify from 'vite-plugin-vuetify'
 const proxy: any = {}
 
 /* proxies the backend calls, >>NOT<< the frontend calls (clicking) */
-// if (process.env.NODE_ENV === 'development') {
-//   const api = 'http://localhost'
-//   proxy['/api'] = api
-//   proxy['/pid'] = {
-//     target: api + '/api',
-//     changeOrigin: true,
-//     pathRewrite: {
-//       '^/pid': '/pid'
-//     }
-//   }
-//   process.env.NUXT_PUBLIC_API_SERVER = api
-// }
+if (process.env.NODE_ENV === 'development') {
+  const api = 'http://localhost'
+  proxy['/api'] = api
+  proxy['/pid'] = {
+    target: api + '/api',
+    changeOrigin: true,
+    pathRewrite: {
+      '^/pid': '/pid'
+    }
+  }
+  process.env.NUXT_PUBLIC_API_SERVER = api
+}
 
 /**
  * https://nuxt.com/docs/guide/concepts/rendering#hybrid-rendering
@@ -75,8 +75,8 @@ export default defineNuxtConfig({
         }
       },
       api: {
-        client: 'https://dbrepo.arisnet.ac.at',
-        server: 'https://dbrepo.arisnet.ac.at',
+        client: 'http://localhost',
+        server: 'http://gateway-service',
       },
       upload: {
         client: 'http://localhost/api/upload/files',
diff --git a/dbrepo-ui/package.json b/dbrepo-ui/package.json
index 856f56f4f0294cbc555f7d8d0a3d2e931d45ea58..a1354778200ebabb28a575e204e264e6bd155774 100644
--- a/dbrepo-ui/package.json
+++ b/dbrepo-ui/package.json
@@ -23,6 +23,7 @@
     "buffer": "^6.0.3",
     "chart.js": "^4.4.1",
     "date-fns": "^3.3.1",
+    "http-status-codes": "^2.3.0",
     "jwt-decode": "^4.0.0",
     "merkle-json": "^2.6.0",
     "moment": "^2.30.1",
diff --git a/dbrepo-ui/pages/database/[database_id]/info.vue b/dbrepo-ui/pages/database/[database_id]/info.vue
index eee94047bc3aaeb922f70f65faaabf3a28b1244d..02c2c8310ae9bafe8ce458decf6ccdd86a6cba37 100644
--- a/dbrepo-ui/pages/database/[database_id]/info.vue
+++ b/dbrepo-ui/pages/database/[database_id]/info.vue
@@ -161,27 +161,14 @@
       :items="items"
       class="pa-0 mt-2" />
   </div>
-  <JumboBox
-    v-if="error"
-    :title="$t(errorCodeKey(error).title, { resource: 'database' })"
-    :subtitle="$t(errorCodeKey(error).subtitle)"
-    :text="$t(errorCodeKey(error).text, { resource: 'database' })" />
-  <pre v-if="error">{{ error }}</pre>
 </template>
 
-<script setup>
-import { ref } from 'vue'
-
-const runtimeConfig = useRuntimeConfig()
-const config = ref(runtimeConfig)
-</script>
 <script>
 import DatabaseToolbar from '@/components/database/DatabaseToolbar.vue'
 import Summary from '@/components/identifier/Summary.vue'
 import Select from '@/components/identifier/Select.vue'
 import UserBadge from '@/components/user/UserBadge.vue'
-import JumboBox from '@/components/JumboBox.vue'
-import { sizeToHumanLabel, errorCodeKey } from '@/utils'
+import { sizeToHumanLabel } from '@/utils'
 import { useUserStore } from '@/stores/user'
 import { useCacheStore } from '@/stores/cache'
 
@@ -190,32 +177,11 @@ export default {
     DatabaseToolbar,
     Summary,
     Select,
-    UserBadge,
-    JumboBox
-  },
-  setup () {
-    const userStore = useUserStore()
-    const { database_id } = useRoute().params
-    const { error, data } = useFetch(`${this.config.public.api.server}/api/database/${database_id}`, {
-      immediate: true,
-      method: 'GET',
-      timeout: 90_000,
-      headers: {
-        Accept: 'application/json',
-        Authorization: userStore.getToken ? `Bearer ${this.userStore.getToken}` : null
-      }
-    })
-    if (data.value) {
-      const identifierService = useIdentifierService()
-      useServerHead(identifierService.databaseToServerHead(data.value))
-      useServerSeoMeta(identifierService.databaseToServerSeoMeta(data.value))
-    }
-    return {
-      error
-    }
+    UserBadge
   },
   data () {
     return {
+      error: null,
       items: [
         {
           title: this.$t('navigation.databases'),
@@ -375,9 +341,6 @@ export default {
       }
       return this.database
     }
-  },
-  methods: {
-    errorCodeKey
   }
 }
 </script>
diff --git a/dbrepo-ui/pages/database/[database_id]/persist/[identifier_id]/index.vue b/dbrepo-ui/pages/database/[database_id]/persist/[identifier_id]/index.vue
index 7de1348fdce246da3f47d8869f9705d13d5f7c7d..a57b439b216ae4743fd4bda292dc53e5f7e05a69 100644
--- a/dbrepo-ui/pages/database/[database_id]/persist/[identifier_id]/index.vue
+++ b/dbrepo-ui/pages/database/[database_id]/persist/[identifier_id]/index.vue
@@ -1,6 +1,9 @@
 <template>
-  <div v-if="canCreateIdentifier || canUpdateIdentifier">
-    <Persist type="database" :database="database" />
+  <div
+    v-if="canCreateIdentifier || canUpdateIdentifier">
+    <Persist
+      type="database"
+      :database="database" />
     <v-breadcrumbs :items="items" class="pa-0 mt-2" />
   </div>
 </template>
diff --git a/dbrepo-ui/pages/database/[database_id]/persist/index.vue b/dbrepo-ui/pages/database/[database_id]/persist/index.vue
index 0981a547905ad08494c980c3d07dce2242c4ea04..df675d262e8e116b0c4252d74fe6878681388acb 100644
--- a/dbrepo-ui/pages/database/[database_id]/persist/index.vue
+++ b/dbrepo-ui/pages/database/[database_id]/persist/index.vue
@@ -1,6 +1,9 @@
 <template>
-  <div v-if="canCreateIdentifier || canUpdateIdentifier">
-    <Persist type="database" :database="database" />
+  <div
+    v-if="canCreateIdentifier || canUpdateIdentifier">
+    <Persist
+      type="database"
+      :database="database" />
     <v-breadcrumbs :items="items" class="pa-0 mt-2" />
   </div>
 </template>
diff --git a/dbrepo-ui/pages/database/[database_id]/settings.vue b/dbrepo-ui/pages/database/[database_id]/settings.vue
index 984df4e635e0d010a451fcf2efb11019ffc74433..aed13a4e1e3ca25db85b8f905415a55336ba9fa2 100644
--- a/dbrepo-ui/pages/database/[database_id]/settings.vue
+++ b/dbrepo-ui/pages/database/[database_id]/settings.vue
@@ -242,43 +242,18 @@
     </v-window>
     <v-breadcrumbs :items="items" class="pa-0 mt-2" />
   </div>
-  <JumboBox
-    v-if="error"
-    :title="$t(errorCodeKey(error).title, { resource: 'database' })"
-    :subtitle="$t(errorCodeKey(error).subtitle)"
-    :text="$t(errorCodeKey(error).text, { resource: 'database' })" />
 </template>
 
 <script>
 import DatabaseToolbar from '@/components/database/DatabaseToolbar.vue'
 import EditAccess from '@/components/dialogs/EditAccess.vue'
-import JumboBox from '@/components/JumboBox.vue'
 import { useUserStore } from '@/stores/user'
 import { useCacheStore } from '@/stores/cache'
-import { errorCodeKey } from '@/utils'
 
 export default {
   components: {
     DatabaseToolbar,
-    EditAccess,
-    JumboBox
-  },
-  setup () {
-    const config = useRuntimeConfig()
-    const userStore = useUserStore()
-    const { database_id } = useRoute().params
-    const { error } = useFetch(`${config.public.api.server}/api/database/${database_id}`, {
-      immediate: true,
-      method: 'HEAD',
-      timeout: 90_000,
-      headers: {
-        Accept: 'application/json',
-        Authorization: userStore.getToken ? `Bearer ${userStore.getToken}` : null
-      }
-    })
-    return {
-      error
-    }
+    EditAccess
   },
   data () {
     return {
@@ -488,7 +463,6 @@ export default {
     this.modifyOwner.id = this.database.owner.id
   },
   methods: {
-    errorCodeKey,
     submit () {
       this.$refs.form.validate()
     },
diff --git a/dbrepo-ui/pages/database/[database_id]/subset/[subset_id]/data.vue b/dbrepo-ui/pages/database/[database_id]/subset/[subset_id]/data.vue
index 01ebb72efb3c3d61b125b3807962f65915e0feca..37c34a71677e1e8aa92464d43c47d89a95d22a81 100644
--- a/dbrepo-ui/pages/database/[database_id]/subset/[subset_id]/data.vue
+++ b/dbrepo-ui/pages/database/[database_id]/subset/[subset_id]/data.vue
@@ -53,30 +53,12 @@ import QueryResults from '@/components/subset/Results.vue'
 import SubsetToolbar from '@/components/subset/SubsetToolbar.vue'
 import { formatTimestampUTCLabel } from '@/utils'
 import { useCacheStore } from '@/stores/cache'
-import {useUserStore} from "~/stores/user.js";
 
 export default {
   components: {
     SubsetToolbar,
     QueryResults
   },
-  setup () {
-    const config = useRuntimeConfig()
-    const userStore = useUserStore()
-    const { database_id, subset_id } = useRoute().params
-    const { error, data } = useFetch(`${config.public.api.server}/api/database/${database_id}/subset/${subset_id}`, {
-      immediate: true,
-      timeout: 90_000,
-      headers: {
-        Accept: 'application/json',
-        Authorization: userStore.getToken ? `Bearer ${userStore.getToken}` : null
-      }
-    })
-    return {
-      subset: data,
-      error
-    }
-  },
   data () {
     return {
       loadingSubset: false,
@@ -111,6 +93,9 @@ export default {
     database () {
       return this.cacheStore.getDatabase
     },
+    subset () {
+      return this.cacheStore.getSubset
+    },
     executionUTC () {
       if (!this.subset) {
         return null
@@ -186,5 +171,3 @@ export default {
   }
 }
 </script>
-<style>
-</style>
diff --git a/dbrepo-ui/pages/database/[database_id]/subset/[subset_id]/info.vue b/dbrepo-ui/pages/database/[database_id]/subset/[subset_id]/info.vue
index 88add5804efd050bca3c9cd73011724832d3d3cd..f27153bebfc710b82f25fb0cc3d3a92297472aac 100644
--- a/dbrepo-ui/pages/database/[database_id]/subset/[subset_id]/info.vue
+++ b/dbrepo-ui/pages/database/[database_id]/subset/[subset_id]/info.vue
@@ -102,28 +102,6 @@ export default {
     SubsetToolbar,
     UserBadge
   },
-  setup () {
-    const config = useRuntimeConfig()
-    const userStore = useUserStore()
-    const { database_id, subset_id } = useRoute().params
-    const { error, data } = useFetch(`${config.public.api.server}/api/database/${database_id}/subset/${subset_id}`, {
-      immediate: true,
-      timeout: 90_000,
-      headers: {
-        Accept: 'application/json',
-        Authorization: userStore.getToken ? `Bearer ${userStore.getToken}` : null
-      }
-    })
-    if (data.value) {
-      const identifierService = useIdentifierService()
-      useServerHead(identifierService.subsetToServerHead(data.value))
-      useServerSeoMeta(identifierService.subsetToServerSeoMeta(data.value))
-    }
-    return {
-      subset: data,
-      error
-    }
-  },
   data () {
     return {
       items: [
@@ -170,6 +148,9 @@ export default {
     access () {
       return this.userStore.getAccess
     },
+    subset () {
+      return this.cacheStore.getSubset
+    },
     user () {
       return this.userStore.getUser
     },
diff --git a/dbrepo-ui/pages/database/[database_id]/subset/[subset_id]/persist/[identifier_id]/index.vue b/dbrepo-ui/pages/database/[database_id]/subset/[subset_id]/persist/[identifier_id]/index.vue
index a3b7306643fbc455475e882b41b86ae1744ae013..b15ecb3292520979e550f68c7c16ef873638b124 100644
--- a/dbrepo-ui/pages/database/[database_id]/subset/[subset_id]/persist/[identifier_id]/index.vue
+++ b/dbrepo-ui/pages/database/[database_id]/subset/[subset_id]/persist/[identifier_id]/index.vue
@@ -1,6 +1,9 @@
 <template>
-  <div v-if="canCreateIdentifier || canUpdateIdentifier">
-    <Persist type="subset" :database="database" />
+  <div
+    v-if="canCreateIdentifier || canUpdateIdentifier">
+    <Persist
+      type="subset"
+      :database="database" />
     <v-breadcrumbs :items="items" class="pa-0 mt-2" />
   </div>
 </template>
diff --git a/dbrepo-ui/pages/database/[database_id]/subset/[subset_id]/persist/index.vue b/dbrepo-ui/pages/database/[database_id]/subset/[subset_id]/persist/index.vue
index 01ba88a36c32142f68dbdeb94da99c86cdf10197..07be66bc73911c9bd7580991ef2c71c6d36de5bc 100644
--- a/dbrepo-ui/pages/database/[database_id]/subset/[subset_id]/persist/index.vue
+++ b/dbrepo-ui/pages/database/[database_id]/subset/[subset_id]/persist/index.vue
@@ -1,6 +1,10 @@
 <template>
-  <div v-if="canPersistQuery">
-    <Persist type="subset" :database="database" :query="query" />
+  <div
+    v-if="canPersistQuery">
+    <Persist
+      type="subset"
+      :database="database"
+      :query="query" />
     <v-breadcrumbs :items="items" class="pa-0 mt-2" />
   </div>
 </template>
diff --git a/dbrepo-ui/pages/database/[database_id]/subset/create.vue b/dbrepo-ui/pages/database/[database_id]/subset/create.vue
index 5202bc633626e135e263056fa39b5022676c1575..b533dfb1a8e0af06cd1428032ebf188c9d3c4b0f 100644
--- a/dbrepo-ui/pages/database/[database_id]/subset/create.vue
+++ b/dbrepo-ui/pages/database/[database_id]/subset/create.vue
@@ -1,5 +1,6 @@
 <template>
-  <div v-if="canCreateSubset">
+  <div
+    v-if="canCreateSubset">
     <Builder />
     <v-breadcrumbs :items="items" class="pa-0 mt-2" />
   </div>
diff --git a/dbrepo-ui/pages/database/[database_id]/subset/index.vue b/dbrepo-ui/pages/database/[database_id]/subset/index.vue
index 7866e6d5de310d95729268dc3c1f264be20e540b..d031b3f3f654f260099e109cc17f5c61cf0c4eb6 100644
--- a/dbrepo-ui/pages/database/[database_id]/subset/index.vue
+++ b/dbrepo-ui/pages/database/[database_id]/subset/index.vue
@@ -5,39 +5,16 @@
     <SubsetList />
     <v-breadcrumbs :items="items" class="pa-0 mt-2" />
   </div>
-  <JumboBox
-    v-if="error"
-    :title="$t(errorCodeKey(error).title, { resource: 'subset' })"
-    :subtitle="$t(errorCodeKey(error).subtitle)"
-    :text="$t(errorCodeKey(error).text, { resource: 'subset' })" />
 </template>
 
 <script>
 import SubsetList from '@/components/subset/SubsetList.vue'
-import { errorCodeKey } from '@/utils'
 import { useCacheStore } from '@/stores/cache'
 
 export default {
   components: {
     SubsetList
   },
-  setup () {
-    const config = useRuntimeConfig()
-    const userStore = useUserStore()
-    const { database_id } = useRoute().params
-    const { error } = useFetch(`${config.public.api.server}/api/database/${database_id}`, {
-      immediate: true,
-      method: 'HEAD',
-      timeout: 90_000,
-      headers: {
-        Accept: 'application/json',
-        Authorization: userStore.getToken ? `Bearer ${userStore.getToken}` : null
-      }
-    })
-    return {
-      error
-    }
-  },
   data () {
     return {
       items: [
@@ -68,9 +45,6 @@ export default {
       }
       return this.database
     }
-  },
-  methods: {
-    errorCodeKey
   }
 }
 </script>
diff --git a/dbrepo-ui/pages/database/[database_id]/table/[table_id]/data.vue b/dbrepo-ui/pages/database/[database_id]/table/[table_id]/data.vue
index 10c1bc8ccfe9b236b80308c1355b23e2e3213a31..46e7f564a77cb4592c4df36c0bf07f5ce66f8ac1 100644
--- a/dbrepo-ui/pages/database/[database_id]/table/[table_id]/data.vue
+++ b/dbrepo-ui/pages/database/[database_id]/table/[table_id]/data.vue
@@ -102,30 +102,18 @@
     </v-dialog>
     <v-breadcrumbs :items="items" class="pa-0 mt-2" />
   </div>
-  <JumboBox
-    v-if="error"
-    :title="$t(errorCodeKey(error).title, { resource: 'table' })"
-    :subtitle="$t(errorCodeKey(error).subtitle)"
-    :text="$t(errorCodeKey(error).text, { resource: 'table' })" />
 </template>
 
-<script setup>
-import { ref } from 'vue'
-
-const runtimeConfig = useRuntimeConfig()
-const config = ref(runtimeConfig)
-</script>
 <script>
 import TableHistory from '@/components/table/TableHistory.vue'
 import TimeDrift from '@/components/TimeDrift.vue'
 import TableToolbar from '@/components/table/TableToolbar.vue'
-import { errorCodeKey, formatTimestamp } from '@/utils'
+import { formatTimestamp } from '@/utils'
 import { useUserStore } from '@/stores/user'
 import { useCacheStore } from '@/stores/cache'
 import EditTuple from '@/components/dialogs/EditTuple.vue'
 import BlobDownload from '@/components/table/BlobDownload.vue'
 import QueryResults from '@/components/subset/Results.vue'
-import JumboBox from '@/components/JumboBox.vue'
 
 export default {
   components: {
@@ -134,24 +122,7 @@ export default {
     EditTuple,
     TableHistory,
     TableToolbar,
-    TimeDrift,
-    JumboBox
-  },
-  setup () {
-    const userStore = useUserStore()
-    const { database_id, table_id } = useRoute().params
-    const { error } = useFetch(`${this.config.public.api.server}/api/database/${database_id}/table/${table_id}`, {
-      immediate: true,
-      method: 'HEAD',
-      timeout: 90_000,
-      headers: {
-        Accept: 'application/json',
-        Authorization: userStore.getToken ? `Bearer ${userStore.getToken}` : null
-      }
-    })
-    return {
-      error
-    }
+    TimeDrift
   },
   data () {
     return {
@@ -325,7 +296,6 @@ export default {
     this.reload()
   },
   methods: {
-    errorCodeKey,
     addTuple () {
       this.tuple = {}
       this.columns.forEach((c) => {
diff --git a/dbrepo-ui/pages/database/[database_id]/table/[table_id]/import.vue b/dbrepo-ui/pages/database/[database_id]/table/[table_id]/import.vue
index 0e5185470080940abf12d202849e61071768ecf6..9da3e1c9fd9774ca61be0be90af9a7050d6fba3c 100644
--- a/dbrepo-ui/pages/database/[database_id]/table/[table_id]/import.vue
+++ b/dbrepo-ui/pages/database/[database_id]/table/[table_id]/import.vue
@@ -26,46 +26,16 @@
     </v-card>
     <v-breadcrumbs :items="items" class="pa-0 mt-2" />
   </div>
-  <JumboBox
-    v-if="error"
-    :title="$t(errorCodeKey(error).title, { resource: 'table' })"
-    :subtitle="$t(errorCodeKey(error).subtitle)"
-    :text="$t(errorCodeKey(error).text, { resource: 'table' })" />
 </template>
 
-<script setup>
-import { ref } from 'vue'
-
-const runtimeConfig = useRuntimeConfig()
-const config = ref(runtimeConfig)
-</script>
 <script>
 import TableImport from '@/components/table/TableImport.vue'
-import JumboBox from '@/components/JumboBox.vue'
 import { useUserStore } from '@/stores/user'
 import { useCacheStore } from '@/stores/cache'
-import { errorCodeKey } from '@/utils'
 
 export default {
   components: {
-    TableImport,
-    JumboBox
-  },
-  setup () {
-    const userStore = useUserStore()
-    const { database_id, table_id } = useRoute().params
-    const { error } = useFetch(`${this.config.public.api.server}/api/database/${database_id}/table/${table_id}`, {
-      immediate: true,
-      method: 'HEAD',
-      timeout: 90_000,
-      headers: {
-        Accept: 'application/json',
-        Authorization: userStore.getToken ? `Bearer ${userStore.getToken}` : null
-      }
-    })
-    return {
-      error
-    }
+    TableImport
   },
   data () {
     return {
@@ -125,9 +95,6 @@ export default {
       }
       return this.roles.includes('insert-table-data')
     }
-  },
-  methods: {
-    errorCodeKey
   }
 }
 </script>
diff --git a/dbrepo-ui/pages/database/[database_id]/table/[table_id]/info.vue b/dbrepo-ui/pages/database/[database_id]/table/[table_id]/info.vue
index 5171d1861a2b19330b7122ac4fab6c207d41c6f3..8108e0677e040b5ce500b188e64857398a9c3cb6 100644
--- a/dbrepo-ui/pages/database/[database_id]/table/[table_id]/info.vue
+++ b/dbrepo-ui/pages/database/[database_id]/table/[table_id]/info.vue
@@ -116,57 +116,22 @@
     </v-card>
     <v-breadcrumbs :items="items" class="pa-0 mt-2" />
   </div>
-  <JumboBox
-    v-if="error"
-    :title="$t(errorCodeKey(error).title, { resource: 'table' })"
-    :subtitle="$t(errorCodeKey(error).subtitle)"
-    :text="$t(errorCodeKey(error).text, { resource: 'table' })" />
 </template>
 
-<script setup>
-import { ref } from 'vue'
-
-const runtimeConfig = useRuntimeConfig()
-const config = ref(runtimeConfig)
-</script>
 <script>
 import TableToolbar from '@/components/table/TableToolbar.vue'
-import JumboBox from '@/components/JumboBox.vue'
 import Select from '@/components/identifier/Select.vue'
 import Summary from '@/components/identifier/Summary.vue'
 import UserBadge from '@/components/user/UserBadge.vue'
 import { useUserStore } from '@/stores/user'
 import { useCacheStore } from '@/stores/cache'
-import { errorCodeKey } from '@/utils'
 
 export default {
   components: {
     Summary,
     Select,
     TableToolbar,
-    UserBadge,
-    JumboBox
-  },
-  setup () {
-    const userStore = useUserStore()
-    const { database_id, table_id } = useRoute().params
-    const { error, data } = useFetch(`${this.config.public.api.server}/api/database/${database_id}/table/${table_id}`, {
-      immediate: true,
-      method: 'GET',
-      timeout: 90_000,
-      headers: {
-        Accept: 'application/json',
-        Authorization: userStore.getToken ? `Bearer ${userStore.getToken}` : null
-      }
-    })
-    if (data.value) {
-      const identifierService = useIdentifierService()
-      useServerHead(identifierService.databaseToServerHead(data.value))
-      useServerSeoMeta(identifierService.databaseToServerSeoMeta(data.value))
-    }
-    return {
-      error
-    }
+    UserBadge
   },
   data () {
     return {
@@ -319,9 +284,6 @@ export default {
         return this.$t('pages.table.connection.permissions.read')
       }
     }
-  },
-  methods: {
-    errorCodeKey
-  },
+  }
 }
 </script>
diff --git a/dbrepo-ui/pages/database/[database_id]/table/[table_id]/persist/[identifier_id]/index.vue b/dbrepo-ui/pages/database/[database_id]/table/[table_id]/persist/[identifier_id]/index.vue
index d0b72a436e72ce3e59330d0ffd0ec3bc87bcfa29..d444ca4e6229886522e39c0ad8a35b3988fb022e 100644
--- a/dbrepo-ui/pages/database/[database_id]/table/[table_id]/persist/[identifier_id]/index.vue
+++ b/dbrepo-ui/pages/database/[database_id]/table/[table_id]/persist/[identifier_id]/index.vue
@@ -4,46 +4,16 @@
     <Persist type="table" :database="database" />
     <v-breadcrumbs :items="items" class="pa-0 mt-2" />
   </div>
-  <JumboBox
-    v-if="error"
-    :title="$t(errorCodeKey(error).title, { resource: 'identifier' })"
-    :subtitle="$t(errorCodeKey(error).subtitle)"
-    :text="$t(errorCodeKey(error).text, { resource: 'identifier' })" />
 </template>
 
-<script setup>
-import { ref } from 'vue'
-
-const runtimeConfig = useRuntimeConfig()
-const config = ref(runtimeConfig)
-</script>
 <script>
 import Persist from '@/components/identifier/Persist.vue'
-import JumboBox from '@/components/JumboBox.vue'
 import { useUserStore } from '@/stores/user'
 import { useCacheStore } from '@/stores/cache'
-import { errorCodeKey } from '@/utils'
 
 export default {
   components: {
-    Persist,
-    JumboBox
-  },
-  setup () {
-    const userStore = useUserStore()
-    const { database_id, table_id } = useRoute().params
-    const { error } = useFetch(`${this.config.public.api.server}/api/database/${database_id}/table/${table_id}`, {
-      immediate: true,
-      method: 'HEAD',
-      timeout: 90_000,
-      headers: {
-        Accept: 'application/json',
-        Authorization: userStore.getToken ? `Bearer ${userStore.getToken}` : null
-      }
-    })
-    return {
-      error
-    }
+    Persist
   },
   data () {
     return {
@@ -104,9 +74,6 @@ export default {
       }
       return this.roles.includes('modify-identifier-metadata')
     }
-  },
-  methods: {
-    errorCodeKey
   }
 }
 </script>
diff --git a/dbrepo-ui/pages/database/[database_id]/table/[table_id]/persist/index.vue b/dbrepo-ui/pages/database/[database_id]/table/[table_id]/persist/index.vue
index f807001353b72e3591facf67743ff678c8405c07..af5b613df9673387bc4ab660487de4717524ab02 100644
--- a/dbrepo-ui/pages/database/[database_id]/table/[table_id]/persist/index.vue
+++ b/dbrepo-ui/pages/database/[database_id]/table/[table_id]/persist/index.vue
@@ -9,46 +9,16 @@
       :items="items"
       class="pa-0 mt-2" />
   </div>
-  <JumboBox
-    v-if="error"
-    :title="$t(errorCodeKey(error).title, { resource: 'identifier' })"
-    :subtitle="$t(errorCodeKey(error).subtitle)"
-    :text="$t(errorCodeKey(error).text, { resource: 'identifier' })" />
 </template>
 
-<script setup>
-import { ref } from 'vue'
-
-const runtimeConfig = useRuntimeConfig()
-const config = ref(runtimeConfig)
-</script>
 <script>
 import Persist from '@/components/identifier/Persist.vue'
-import JumboBox from '@/components/JumboBox.vue'
 import { useUserStore } from '@/stores/user'
 import { useCacheStore } from '@/stores/cache'
-import { errorCodeKey } from '@/utils'
 
 export default {
   components: {
-    Persist,
-    JumboBox
-  },
-  setup () {
-    const userStore = useUserStore()
-    const { database_id, table_id } = useRoute().params
-    const { error, data } = useFetch(`${this.config.public.api.server}/api/database/${database_id}/table/${table_id}`, {
-      immediate: true,
-      method: 'HEAD',
-      timeout: 90_000,
-      headers: {
-        Accept: 'application/json',
-        Authorization: userStore.getToken ? `Bearer ${userStore.getToken}` : null
-      }
-    })
-    return {
-      error
-    }
+    Persist
   },
   data () {
     return {
@@ -102,9 +72,6 @@ export default {
       const userService = useUserService()
       return userService.hasReadAccess(this.access)
     }
-  },
-  methods: {
-    errorCodeKey
   }
 }
 </script>
diff --git a/dbrepo-ui/pages/database/[database_id]/table/[table_id]/schema.vue b/dbrepo-ui/pages/database/[database_id]/table/[table_id]/schema.vue
index 320ebe3d7564e285c2ee86f872af42d1ab0ae1b7..0c92401672bf743943dc1f35bdef3d42cd0df3d0 100644
--- a/dbrepo-ui/pages/database/[database_id]/table/[table_id]/schema.vue
+++ b/dbrepo-ui/pages/database/[database_id]/table/[table_id]/schema.vue
@@ -118,46 +118,16 @@
       :items="items"
       class="pa-0 mt-2" />
   </div>
-  <JumboBox
-    v-if="error"
-    :title="$t(errorCodeKey(error).title, { resource: 'table' })"
-    :subtitle="$t(errorCodeKey(error).subtitle)"
-    :text="$t(errorCodeKey(error).text, { resource: 'table' })" />
 </template>
 
-<script setup>
-import { ref } from 'vue'
-
-const runtimeConfig = useRuntimeConfig()
-const config = ref(runtimeConfig)
-</script>
 <script>
 import TableToolbar from '@/components/table/TableToolbar.vue'
-import JumboBox from '@/components/JumboBox.vue'
 import { useUserStore } from '@/stores/user'
 import { useCacheStore } from '@/stores/cache'
-import { errorCodeKey } from '@/utils'
 
 export default {
   components: {
-    TableToolbar,
-    JumboBox
-  },
-  setup () {
-    const userStore = useUserStore()
-    const { database_id, table_id } = useRoute().params
-    const { error } = useFetch(`${this.config.public.api.server}/api/database/${database_id}/table/${table_id}`, {
-      immediate: true,
-      method: 'HEAD',
-      timeout: 90_000,
-      headers: {
-        Accept: 'application/json',
-        Authorization: userStore.getToken ? `Bearer ${userStore.getToken}` : null
-      }
-    })
-    return {
-      error
-    }
+    TableToolbar
   },
   data () {
     return {
@@ -268,7 +238,6 @@ export default {
     }
   },
   methods: {
-    errorCodeKey,
     extra (column) {
       if (column.type === 'float') {
         return `precision=${column.size}`
diff --git a/dbrepo-ui/pages/database/[database_id]/table/[table_id]/settings.vue b/dbrepo-ui/pages/database/[database_id]/table/[table_id]/settings.vue
index f51851b220bc5a6b92f0963d4b06e87285cd3ced..201917c5c051ffd63028fdb7f6f631e9b0dafce7 100644
--- a/dbrepo-ui/pages/database/[database_id]/table/[table_id]/settings.vue
+++ b/dbrepo-ui/pages/database/[database_id]/table/[table_id]/settings.vue
@@ -112,46 +112,17 @@
       :items="items"
       class="pa-0 mt-2" />
   </div>
-  <JumboBox
-    v-if="error"
-    :title="$t(errorCodeKey(error).title, { resource: 'table' })"
-    :subtitle="$t(errorCodeKey(error).subtitle)"
-    :text="$t(errorCodeKey(error).text, { resource: 'table' })" />
 </template>
 
-<script setup>
-import { ref } from 'vue'
-
-const runtimeConfig = useRuntimeConfig()
-const config = ref(runtimeConfig)
-</script>
 <script>
-import JumboBox from '@/components/JumboBox.vue'
 import TableToolbar from '@/components/table/TableToolbar.vue'
 import { useUserStore } from '@/stores/user'
 import { useCacheStore } from '@/stores/cache'
-import { errorCodeKey, max } from '@/utils'
+import { max } from '@/utils'
 
 export default {
   components: {
-    TableToolbar,
-    JumboBox
-  },
-  setup () {
-    const userStore = useUserStore()
-    const { database_id, table_id } = useRoute().params
-    const { error } = useFetch(`${this.config.public.api.server}/api/database/${database_id}/table/${table_id}`, {
-      immediate: true,
-      method: 'HEAD',
-      timeout: 90_000,
-      headers: {
-        Accept: 'application/json',
-        Authorization: userStore.getToken ? `Bearer ${userStore.getToken}` : null
-      }
-    })
-    return {
-      error
-    }
+    TableToolbar
   },
   data () {
     return {
@@ -283,7 +254,6 @@ export default {
   },
   methods: {
     max,
-    errorCodeKey,
     submit () {
       this.$refs.form.validate()
     },
diff --git a/dbrepo-ui/pages/database/[database_id]/table/create/dataset.vue b/dbrepo-ui/pages/database/[database_id]/table/create/dataset.vue
index 2d1729d7cdb2802c8426aa613848b5a9d84d53ce..b031c846ea41b1e3932197401aba95afc9acbb9e 100644
--- a/dbrepo-ui/pages/database/[database_id]/table/create/dataset.vue
+++ b/dbrepo-ui/pages/database/[database_id]/table/create/dataset.vue
@@ -217,22 +217,11 @@
     </v-form>
     <v-breadcrumbs :items="items" class="pa-0 mt-2"/>
   </div>
-  <JumboBox
-    v-if="error"
-    :title="$t(errorCodeKey(error).title, { resource: 'table' })"
-    :subtitle="$t(errorCodeKey(error).subtitle)"
-    :text="$t(errorCodeKey(error).text, { resource: 'table' })" />
 </template>
 
-<script setup>
-import { ref } from 'vue'
-
-const runtimeConfig = useRuntimeConfig()
-const config = ref(runtimeConfig)
-</script>
 <script>
 import TableSchema from '@/components/table/TableSchema.vue'
-import { notEmpty, errorCodeKey } from '@/utils'
+import { notEmpty } from '@/utils'
 import { useUserStore } from '@/stores/user'
 import { useCacheStore } from '@/stores/cache'
 
@@ -240,22 +229,6 @@ export default {
   components: {
     TableSchema
   },
-  setup () {
-    const userStore = useUserStore()
-    const { database_id } = useRoute().params
-    const { error } = useFetch(`${this.config.public.api.server}/api/database/${database_id}`, {
-      immediate: true,
-      method: 'HEAD',
-      timeout: 90_000,
-      headers: {
-        Accept: 'application/json',
-        Authorization: userStore.getToken ? `Bearer ${userStore.getToken}` : null
-      }
-    })
-    return {
-      error
-    }
-  },
   data() {
     return {
       step: 1,
@@ -392,7 +365,6 @@ export default {
   },
   methods: {
     notEmpty,
-    errorCodeKey,
     submit() {
       this.$refs.form.validate()
     },
diff --git a/dbrepo-ui/pages/database/[database_id]/table/create/schema.vue b/dbrepo-ui/pages/database/[database_id]/table/create/schema.vue
index 946b084ba87a1440abfe7fc58b592d9067733688..5f433013bf30d4a450efba6228eb9f693673514f 100644
--- a/dbrepo-ui/pages/database/[database_id]/table/create/schema.vue
+++ b/dbrepo-ui/pages/database/[database_id]/table/create/schema.vue
@@ -183,30 +183,17 @@
     </v-card>
     <v-breadcrumbs :items="items" class="pa-0 mt-2" />
   </div>
-  <JumboBox
-    v-if="error"
-    :title="$t(errorCodeKey(error).title, { resource: 'table' })"
-    :subtitle="$t(errorCodeKey(error).subtitle)"
-    :text="$t(errorCodeKey(error).text, { resource: 'table' })" />
 </template>
 
-<script setup>
-import { ref } from 'vue'
-
-const runtimeConfig = useRuntimeConfig()
-const config = ref(runtimeConfig)
-</script>
 <script>
 import TableSchema from '@/components/table/TableSchema.vue'
-import JumboBox from '@/components/JumboBox.vue'
-import { notEmpty, errorCodeKey } from '@/utils'
+import { notEmpty } from '@/utils'
 import { useUserStore } from '@/stores/user'
 import { useCacheStore } from '@/stores/cache'
 
 export default {
   components: {
-    TableSchema,
-    JumboBox
+    TableSchema
   },
   data () {
     return {
@@ -320,7 +307,6 @@ export default {
   },
   methods: {
     notEmpty,
-    errorCodeKey,
     submit () {
       this.$refs.form.validate()
     },
diff --git a/dbrepo-ui/pages/database/[database_id]/table/index.vue b/dbrepo-ui/pages/database/[database_id]/table/index.vue
index 6511f963c6dcdeb50f67f7ee5b96f7e620f6a1a3..2f1cf87ec800162f2be19e05916cc99224f26c4a 100644
--- a/dbrepo-ui/pages/database/[database_id]/table/index.vue
+++ b/dbrepo-ui/pages/database/[database_id]/table/index.vue
@@ -10,24 +10,12 @@
       :items="items"
       class="pa-0 mt-2" />
   </div>
-  <JumboBox
-    v-if="error"
-    :title="$t(errorCodeKey(error).title, { resource: 'table' })"
-    :subtitle="$t(errorCodeKey(error).subtitle)"
-    :text="$t(errorCodeKey(error).text, { resource: 'table' })" />
 </template>
 
-<script setup>
-import { ref } from 'vue'
-
-const runtimeConfig = useRuntimeConfig()
-const config = ref(runtimeConfig)
-</script>
 <script>
 import TableList from '@/components/table/TableList.vue'
 import DatabaseToolbar from '@/components/database/DatabaseToolbar.vue'
 import { useCacheStore } from '@/stores/cache'
-import { errorCodeKey } from '@/utils'
 
 export default {
   name: 'Tables',
@@ -35,22 +23,6 @@ export default {
     TableList,
     DatabaseToolbar
   },
-  setup () {
-    const userStore = useUserStore()
-    const { database_id } = useRoute().params
-    const { error } = useFetch(`${this.config.public.api.server}/api/database/${database_id}`, {
-      immediate: true,
-      method: 'HEAD',
-      timeout: 90_000,
-      headers: {
-        Accept: 'application/json',
-        Authorization: userStore.getToken ? `Bearer ${userStore.getToken}` : null
-      }
-    })
-    return {
-      error
-    }
-  },
   data () {
     return {
       tab: 0,
@@ -82,9 +54,6 @@ export default {
       }
       return this.database
     }
-  },
-  methods: {
-    errorCodeKey
   }
 }
 </script>
diff --git a/dbrepo-ui/pages/database/[database_id]/view/[view_id]/data.vue b/dbrepo-ui/pages/database/[database_id]/view/[view_id]/data.vue
index 3f0ebc184451afac8b513dd594ab3526b854cdff..f4c81f43f0bdd08a1984e5cd23c8af8c1bb003e4 100644
--- a/dbrepo-ui/pages/database/[database_id]/view/[view_id]/data.vue
+++ b/dbrepo-ui/pages/database/[database_id]/view/[view_id]/data.vue
@@ -32,47 +32,17 @@
     </v-card>
     <v-breadcrumbs :items="items" class="pa-0 mt-2" />
   </div>
-  <JumboBox
-    v-if="error"
-    :title="$t(errorCodeKey(error).title, { resource: 'view' })"
-    :subtitle="$t(errorCodeKey(error).subtitle)"
-    :text="$t(errorCodeKey(error).text, { resource: 'view' })" />
 </template>
 
-<script setup>
-import { ref } from 'vue'
-
-const runtimeConfig = useRuntimeConfig()
-const config = ref(runtimeConfig)
-</script>
 <script>
 import TimeDrift from '@/components/TimeDrift.vue'
-import JumboBox from '@/components/JumboBox.vue'
 import QueryResults from '@/components/subset/Results.vue'
 import { useUserStore } from '@/stores/user'
-import { errorCodeKey } from '@/utils'
 
 export default {
   components: {
     QueryResults,
-    TimeDrift,
-    JumboBox
-  },
-  setup () {
-    const userStore = useUserStore()
-    const { database_id, view_id } = useRoute().params
-    const { error } = useFetch(`${this.config.public.api.server}/api/database/${database_id}/view/${view_id}`, {
-      immediate: true,
-      method: 'HEAD',
-      timeout: 90_000,
-      headers: {
-        Accept: 'application/json',
-        Authorization: userStore.getToken ? `Bearer ${userStore.getToken}` : null
-      }
-    })
-    return {
-      error
-    }
+    TimeDrift
   },
   data () {
     return {
@@ -143,7 +113,6 @@ export default {
     this.reload()
   },
   methods: {
-    errorCodeKey,
     reload () {
       this.$refs.queryResults.reExecute(Number(this.$route.params.view_id))
       this.$refs.queryResults.reExecuteCount(Number(this.$route.params.view_id))
diff --git a/dbrepo-ui/pages/database/[database_id]/view/[view_id]/info.vue b/dbrepo-ui/pages/database/[database_id]/view/[view_id]/info.vue
index 61bdb4c3796df94cbdf40245dc3fa887ebe67cad..43bfb2b39028857833ba0c15ce09a125141a28f3 100644
--- a/dbrepo-ui/pages/database/[database_id]/view/[view_id]/info.vue
+++ b/dbrepo-ui/pages/database/[database_id]/view/[view_id]/info.vue
@@ -57,26 +57,14 @@
     </v-window>
     <v-breadcrumbs :items="items" class="pa-0 mt-2" />
   </div>
-  <JumboBox
-    v-if="error"
-    :title="$t(errorCodeKey(error).title, { resource: 'view' })"
-    :subtitle="$t(errorCodeKey(error).subtitle)"
-    :text="$t(errorCodeKey(error).text, { resource: 'view' })" />
 </template>
 
-<script setup>
-import { ref } from 'vue'
-
-const runtimeConfig = useRuntimeConfig()
-const config = ref(runtimeConfig)
-</script>
 <script>
 import ViewToolbar from '@/components/view/ViewToolbar.vue'
 import Summary from '@/components/identifier/Summary.vue'
 import Select from '@/components/identifier/Select.vue'
 import UserBadge from '@/components/user/UserBadge.vue'
-import JumboBox from '@/components/JumboBox.vue'
-import { formatTimestampUTCLabel, errorCodeKey } from '@/utils'
+import { formatTimestampUTCLabel } from '@/utils'
 import { useUserStore } from '@/stores/user'
 import { useCacheStore } from '@/stores/cache'
 
@@ -85,30 +73,7 @@ export default {
     Select,
     Summary,
     ViewToolbar,
-    UserBadge,
-    JumboBox
-  },
-  setup () {
-    const userStore = useUserStore()
-    const { database_id, view_id } = useRoute().params
-    const { error, data } = useFetch(`${this.config.public.api.server}/api/database/${database_id}/view/${view_id}`, {
-      immediate: true,
-      method: 'GET',
-      timeout: 90_000,
-      headers: {
-        Accept: 'application/json',
-        Authorization: userStore.getToken ? `Bearer ${userStore.getToken}` : null
-      }
-    })
-    if (data.value) {
-      const identifierService = useIdentifierService()
-      useServerHead(identifierService.viewToServerHead(data.value))
-      useServerSeoMeta(identifierService.viewToServerSeoMeta(data.value))
-    }
-    return {
-      view: data,
-      error
-    }
+    UserBadge
   },
   data () {
     return {
@@ -221,7 +186,6 @@ export default {
     }
   },
   methods: {
-    errorCodeKey,
     formatUTC (timestamp) {
       return formatTimestampUTCLabel(timestamp)
     }
diff --git a/dbrepo-ui/pages/database/[database_id]/view/[view_id]/persist/[identifier_id]/index.vue b/dbrepo-ui/pages/database/[database_id]/view/[view_id]/persist/[identifier_id]/index.vue
index 11b0f60c00bd0e19e9a89d2acaf3d5bae78da3a2..86db06f1963fb3e491a939ca389d913db7da473d 100644
--- a/dbrepo-ui/pages/database/[database_id]/view/[view_id]/persist/[identifier_id]/index.vue
+++ b/dbrepo-ui/pages/database/[database_id]/view/[view_id]/persist/[identifier_id]/index.vue
@@ -6,46 +6,16 @@
       :database="database" />
     <v-breadcrumbs :items="items" class="pa-0 mt-2" />
   </div>
-  <JumboBox
-    v-if="error"
-    :title="$t(errorCodeKey(error).title, { resource: 'view' })"
-    :subtitle="$t(errorCodeKey(error).subtitle)"
-    :text="$t(errorCodeKey(error).text, { resource: 'view' })" />
 </template>
 
-<script setup>
-import { ref } from 'vue'
-
-const runtimeConfig = useRuntimeConfig()
-const config = ref(runtimeConfig)
-</script>
 <script>
 import Persist from '@/components/identifier/Persist.vue'
-import JumboBox from '@/components/JumboBox.vue'
 import { useUserStore } from '@/stores/user'
 import { useCacheStore } from '@/stores/cache'
-import { errorCodeKey } from '@/utils'
 
 export default {
   components: {
-    Persist,
-    JumboBox
-  },
-  setup () {
-    const userStore = useUserStore()
-    const { database_id, view_id } = useRoute().params
-    const { error } = useFetch(`${this.config.public.api.server}/api/database/${database_id}/view/${view_id}`, {
-      immediate: true,
-      method: 'HEAD',
-      timeout: 90_000,
-      headers: {
-        Accept: 'application/json',
-        Authorization: userStore.getToken ? `Bearer ${userStore.getToken}` : null
-      }
-    })
-    return {
-      error
-    }
+    Persist
   },
   data () {
     return {
@@ -106,9 +76,6 @@ export default {
       }
       return this.roles.includes('modify-identifier-metadata')
     }
-  },
-  methods: {
-    errorCodeKey
   }
 }
 </script>
diff --git a/dbrepo-ui/pages/database/[database_id]/view/[view_id]/persist/index.vue b/dbrepo-ui/pages/database/[database_id]/view/[view_id]/persist/index.vue
index 3a2f0f793fe85ccbbd1473b3c513b5060449327a..f3a3e18f9df142e3f136caf3d022c218676dfb41 100644
--- a/dbrepo-ui/pages/database/[database_id]/view/[view_id]/persist/index.vue
+++ b/dbrepo-ui/pages/database/[database_id]/view/[view_id]/persist/index.vue
@@ -7,46 +7,16 @@
       :view="view" />
     <v-breadcrumbs :items="items" class="pa-0 mt-2" />
   </div>
-  <JumboBox
-    v-if="error"
-    :title="$t(errorCodeKey(error).title, { resource: 'view' })"
-    :subtitle="$t(errorCodeKey(error).subtitle)"
-    :text="$t(errorCodeKey(error).text, { resource: 'view' })" />
 </template>
 
-<script setup>
-import { ref } from 'vue'
-
-const runtimeConfig = useRuntimeConfig()
-const config = ref(runtimeConfig)
-</script>
 <script>
 import Persist from '@/components/identifier/Persist.vue'
-import JumboBox from '@/components/JumboBox.vue'
 import { useUserStore } from '@/stores/user'
 import { useCacheStore } from '@/stores/cache'
-import { errorCodeKey } from '@/utils'
 
 export default {
   components: {
-    Persist,
-    JumboBox
-  },
-  setup () {
-    const userStore = useUserStore()
-    const { database_id, view_id } = useRoute().params
-    const { error } = useFetch(`${this.config.public.api.server}/api/database/${database_id}/view/${view_id}`, {
-      immediate: true,
-      method: 'HEAD',
-      timeout: 90_000,
-      headers: {
-        Accept: 'application/json',
-        Authorization: userStore.getToken ? `Bearer ${userStore.getToken}` : null
-      }
-    })
-    return {
-      error
-    }
+    Persist
   },
   data () {
     return {
@@ -102,9 +72,6 @@ export default {
       const userService = useUserService()
       return userService.hasReadAccess(this.access)
     }
-  },
-  methods: {
-    errorCodeKey
   }
 }
 </script>
diff --git a/dbrepo-ui/pages/database/[database_id]/view/[view_id]/schema.vue b/dbrepo-ui/pages/database/[database_id]/view/[view_id]/schema.vue
index e8a8435d88f18b741705d34430a8c3a365925ec0..e126e19d9050c23b4299f9799b2895490813f33f 100644
--- a/dbrepo-ui/pages/database/[database_id]/view/[view_id]/schema.vue
+++ b/dbrepo-ui/pages/database/[database_id]/view/[view_id]/schema.vue
@@ -49,46 +49,16 @@
       :items="items"
       class="pa-0 mt-2" />
   </div>
-  <JumboBox
-    v-if="error"
-    :title="$t(errorCodeKey(error).title, { resource: 'view' })"
-    :subtitle="$t(errorCodeKey(error).subtitle)"
-    :text="$t(errorCodeKey(error).text, { resource: 'view' })" />
 </template>
 
-<script setup>
-import { ref } from 'vue'
-
-const runtimeConfig = useRuntimeConfig()
-const config = ref(runtimeConfig)
-</script>
 <script>
 import TableToolbar from '@/components/table/TableToolbar.vue'
-import JumboBox from '@/components/JumboBox.vue'
 import { useUserStore } from '@/stores/user'
 import { useCacheStore } from '@/stores/cache'
-import { errorCodeKey } from '@/utils'
 
 export default {
   components: {
-    TableToolbar,
-    JumboBox
-  },
-  setup () {
-    const userStore = useUserStore()
-    const { database_id, view_id } = useRoute().params
-    const { error } = useFetch(`${this.config.public.api.server}/api/database/${database_id}/view/${view_id}`, {
-      immediate: true,
-      method: 'HEAD',
-      timeout: 90_000,
-      headers: {
-        Accept: 'application/json',
-        Authorization: userStore.getToken ? `Bearer ${userStore.getToken}` : null
-      }
-    })
-    return {
-      error
-    }
+    TableToolbar
   },
   data () {
     return {
@@ -173,7 +143,6 @@ export default {
     }
   },
   methods: {
-    errorCodeKey,
     extra (column) {
       if (column.type === 'float') {
         return `precision=${column.size}`
diff --git a/dbrepo-ui/pages/database/[database_id]/view/[view_id]/settings.vue b/dbrepo-ui/pages/database/[database_id]/view/[view_id]/settings.vue
index 8a65a34f274081cf289099354edc142392492ae2..27444c9e89aec8cb2f9fb915504f3f9a4aaa97f1 100644
--- a/dbrepo-ui/pages/database/[database_id]/view/[view_id]/settings.vue
+++ b/dbrepo-ui/pages/database/[database_id]/view/[view_id]/settings.vue
@@ -88,46 +88,16 @@
       :items="items"
       class="pa-0 mt-2" />
   </div>
-  <JumboBox
-    v-if="error"
-    :title="$t(errorCodeKey(error).title, { resource: 'view' })"
-    :subtitle="$t(errorCodeKey(error).subtitle)"
-    :text="$t(errorCodeKey(error).text, { resource: 'view' })" />
 </template>
 
-<script setup>
-import { ref } from 'vue'
-
-const runtimeConfig = useRuntimeConfig()
-const config = ref(runtimeConfig)
-</script>
 <script>
 import ViewToolbar from '@/components/view/ViewToolbar.vue'
-import JumboBox from '@/components/JumboBox.vue'
 import { useUserStore } from '@/stores/user'
 import { useCacheStore } from '@/stores/cache'
-import { errorCodeKey } from '@/utils'
 
 export default {
   components: {
-    ViewToolbar,
-    JumboBox
-  },
-  setup () {
-    const userStore = useUserStore()
-    const { database_id } = useRoute().params
-    const { error } = useFetch(`${this.config.public.api.server}/api/database/${database_id}`, {
-      immediate: true,
-      method: 'HEAD',
-      timeout: 90_000,
-      headers: {
-        Accept: 'application/json',
-        Authorization: userStore.getToken ? `Bearer ${userStore.getToken}` : null
-      }
-    })
-    return {
-      error
-    }
+    ViewToolbar
   },
   data () {
     return {
@@ -252,7 +222,6 @@ export default {
     this.modify.description = this.view.description
   },
   methods: {
-    errorCodeKey,
     submit () {
       this.$refs.form.validate()
     },
diff --git a/dbrepo-ui/pages/database/[database_id]/view/create.vue b/dbrepo-ui/pages/database/[database_id]/view/create.vue
index d1202980ecb542ee89a940da11d3fa159f28b106..060d186252e1192b3264af89b92b85293ad14d09 100644
--- a/dbrepo-ui/pages/database/[database_id]/view/create.vue
+++ b/dbrepo-ui/pages/database/[database_id]/view/create.vue
@@ -4,45 +4,15 @@
     <Builder mode="view" />
     <v-breadcrumbs :items="items" class="pa-0 mt-2" />
   </div>
-  <JumboBox
-    v-if="error"
-    :title="$t(errorCodeKey(error).title, { resource: 'view' })"
-    :subtitle="$t(errorCodeKey(error).subtitle)"
-    :text="$t(errorCodeKey(error).text, { resource: 'view' })" />
 </template>
 
-<script setup>
-import { ref } from 'vue'
-
-const runtimeConfig = useRuntimeConfig()
-const config = ref(runtimeConfig)
-</script>
 <script>
 import Builder from '@/components/subset/Builder.vue'
-import JumboBox from '@/components/JumboBox.vue'
 import { useUserStore } from '@/stores/user'
-import { errorCodeKey } from '@/utils'
 
 export default {
   components: {
-    Builder,
-    JumboBox
-  },
-  setup () {
-    const userStore = useUserStore()
-    const { database_id } = useRoute().params
-    const { error } = useFetch(`${this.config.public.api.server}/api/database/${database_id}`, {
-      immediate: true,
-      method: 'HEAD',
-      timeout: 90_000,
-      headers: {
-        Accept: 'application/json',
-        Authorization: userStore.getToken ? `Bearer ${userStore.getToken}` : null
-      }
-    })
-    return {
-      error
-    }
+    Builder
   },
   data () {
     return {
@@ -81,9 +51,6 @@ export default {
       }
       return this.roles.includes('create-database-view')
     }
-  },
-  methods: {
-    errorCodeKey
   }
 }
 </script>
diff --git a/dbrepo-ui/pages/database/[database_id]/view/index.vue b/dbrepo-ui/pages/database/[database_id]/view/index.vue
index ab244bbe8a11453d2fc8bdb61de5e9773d4af80b..4172797328151393813f683200652c2753e783ed 100644
--- a/dbrepo-ui/pages/database/[database_id]/view/index.vue
+++ b/dbrepo-ui/pages/database/[database_id]/view/index.vue
@@ -10,49 +10,18 @@
       :items="items"
       class="pa-0 mt-2" />
   </div>
-  <JumboBox
-    v-if="error"
-    :title="$t(errorCodeKey(error).title, { resource: 'view' })"
-    :subtitle="$t(errorCodeKey(error).subtitle)"
-    :text="$t(errorCodeKey(error).text, { resource: 'view' })" />
 </template>
 
-<script setup>
-import { ref } from 'vue'
-
-const runtimeConfig = useRuntimeConfig()
-const config = ref(runtimeConfig)
-</script>
 <script>
 import DatabaseToolbar from '@/components/database/DatabaseToolbar.vue'
-import JumboBox from '@/components/JumboBox.vue'
 import ViewList from '@/components/view/ViewList.vue'
 import { useCacheStore } from '@/stores/cache'
-import { errorCodeKey } from '@/utils'
 
 export default {
   name: 'Views',
   components: {
     ViewList,
-    DatabaseToolbar,
-    JumboBox
-  },
-  setup () {
-    const config = useRuntimeConfig()
-    const userStore = useUserStore()
-    const { database_id } = useRoute().params
-    const { error } = useFetch(`${this.config.public.api.server}/api/database/${database_id}`, {
-      immediate: true,
-      method: 'HEAD',
-      timeout: 90_000,
-      headers: {
-        Accept: 'application/json',
-        Authorization: userStore.getToken ? `Bearer ${userStore.getToken}` : null
-      }
-    })
-    return {
-      error
-    }
+    DatabaseToolbar
   },
   data () {
     return {
@@ -85,9 +54,6 @@ export default {
       }
       return this.database
     }
-  },
-  methods: {
-    errorCodeKey
   }
 }
 </script>
diff --git a/dbrepo-ui/pages/search.vue b/dbrepo-ui/pages/search.vue
index d822643204c47860ef8a9be87a8a25b3571bdadb..b13a0f0fc2d7985775fe8c3c450c0acb8785bbd0 100644
--- a/dbrepo-ui/pages/search.vue
+++ b/dbrepo-ui/pages/search.vue
@@ -52,6 +52,8 @@
           <div
             v-if="tags(result).length > 0"
             class="mt-2 db-tags">
+            <ResourceStatus
+              :resource="result" />
             <v-chip
               v-for="(tag, i) in tags(result)"
               :key="i"
@@ -196,12 +198,6 @@ export default {
       }
       return this.type === 'identifier'
     },
-    isPublic (item) {
-      if (this.isDatabase(item) || this.isTable(item) || this.isColumn(item) || this.isView(item) || this.isIdentifier(item)) {
-        return item.is_public
-      }
-      return null
-    },
     title (item) {
       if (this.isDatabase(item) || this.isTable(item) || this.isColumn(item) || this.isView(item)) {
         return item.name
@@ -260,10 +256,6 @@ export default {
     },
     tags (item) {
       const tags = []
-      if (this.isPublic(item) === true || this.isPublic(item) === false) {
-        const text = this.isPublic(item) ? this.$t('toolbars.database.public') : this.$t('toolbars.database.private')
-        tags.push({ color: this.isPublic(item) ? 'success' : null, text })
-      }
       if (this.isDatabase(item)) {
       } else if (this.isTable(item)) {
       } else if (this.isColumn(item)) {
diff --git a/dbrepo-ui/stores/cache.js b/dbrepo-ui/stores/cache.js
index 13fcea5861eae8fe3c086536a67a69950ba721fb..3574b24d7c6300b884f7874726254e3c805393b3 100644
--- a/dbrepo-ui/stores/cache.js
+++ b/dbrepo-ui/stores/cache.js
@@ -23,25 +23,25 @@ export const useCacheStore = defineStore('cache', {
     getUploadProgress: (state) => state.uploadProgress,
   },
   actions: {
-    setDatabase (database) {
+    setDatabase(database) {
       this.database = database
     },
-    setTable (table) {
+    setTable(table) {
       this.table = table
     },
-    setView (view) {
+    setView(view) {
       this.view = view
     },
-    setSubset (subset) {
+    setSubset(subset) {
       this.subset = subset
     },
-    setOntologies (ontologies) {
+    setOntologies(ontologies) {
       this.ontologies = ontologies
     },
-    setUploadProgress (uploadProgress) {
+    setUploadProgress(uploadProgress) {
       this.uploadProgress = uploadProgress
     },
-    reloadMessages () {
+    reloadMessages() {
       const messageService = useMessageService()
       messageService.findAll('active')
         .then(messages => this.messages = messages)
@@ -49,7 +49,7 @@ export const useCacheStore = defineStore('cache', {
           console.error('Failed to reload messages', error)
         })
     },
-    reloadOntologies () {
+    reloadOntologies() {
       const ontologyService = useOntologyService()
       ontologyService.findAll()
         .then(ontologies => this.ontologies = ontologies)
@@ -57,7 +57,7 @@ export const useCacheStore = defineStore('cache', {
           console.error('Failed to reload ontologies', error)
         })
     },
-    reloadDatabase () {
+    reloadDatabase() {
       const databaseService = useDatabaseService()
       databaseService.findOne(this.database.id)
         .then(database => this.database = database)
@@ -65,7 +65,7 @@ export const useCacheStore = defineStore('cache', {
           console.error('Failed to reload database', error)
         })
     },
-    reloadTable () {
+    reloadTable() {
       const tableService = useTableService()
       tableService.findOne(this.table.database_id, this.table.id)
         .then(table => this.table = table)
@@ -73,7 +73,7 @@ export const useCacheStore = defineStore('cache', {
           console.error('Failed to reload table', error)
         })
     },
-    reloadView () {
+    reloadView() {
       const viewService = useViewService()
       viewService.findOne(this.table.database_id, this.view.id)
         .then(view => this.view = view)
@@ -82,19 +82,24 @@ export const useCacheStore = defineStore('cache', {
         })
     },
     setRouteDatabase (databaseId) {
-      if (!databaseId) {
-        this.database = null
-        return
-      }
-      const databaseService = useDatabaseService()
-      databaseService.findOne(databaseId)
-        .then(database => this.database = database)
-        .catch((error) => {
+      return new Promise((resolve, reject) => {
+        if (!databaseId) {
           this.database = null
-          console.error('Failed to set route database', error)
-        })
+          reject()
+        }
+        const databaseService = useDatabaseService()
+        databaseService.findOne(databaseId, true)
+          .then((database) => {
+            this.database = database
+            resolve(database)
+          })
+          .catch((error) => {
+            this.database = null
+            reject(error)
+          })
+      })
     },
-    setRouteTable (databaseId, tableId) {
+    setRouteTable(databaseId, tableId) {
       if (!databaseId || !tableId) {
         this.table = null
         console.error('Cannot set route table: missing database id', databaseId, 'or table id', tableId)
@@ -103,11 +108,8 @@ export const useCacheStore = defineStore('cache', {
       const tableService = useTableService()
       tableService.findOne(databaseId, tableId)
         .then(table => this.table = table)
-        .catch((error) => {
-          console.error('Failed to set route table', error)
-        })
     },
-    setRouteView (databaseId, viewId) {
+    setRouteView(databaseId, viewId) {
       if (!databaseId || !viewId) {
         this.view = null
         console.error('Cannot set route view: database view id', databaseId, 'or view id', viewId)
@@ -116,11 +118,8 @@ export const useCacheStore = defineStore('cache', {
       const viewService = useViewService()
       viewService.findOne(databaseId, viewId)
         .then(view => this.view = view)
-        .catch((error) => {
-          console.error('Failed to set route view', error)
-        })
     },
-    setRouteSubset (databaseId, subsetId) {
+    setRouteSubset(databaseId, subsetId) {
       if (!databaseId || !subsetId) {
         this.subset = null
         console.error('Cannot set route subset: missing database id', databaseId, 'or subset id', subsetId)
@@ -129,9 +128,6 @@ export const useCacheStore = defineStore('cache', {
       const subsetService = useQueryService()
       subsetService.findOne(databaseId, subsetId)
         .then(subset => this.subset = subset)
-        .catch((error) => {
-          console.error('Failed to set route subset', error)
-        })
     }
   },
 })
diff --git a/dbrepo-ui/utils/index.ts b/dbrepo-ui/utils/index.ts
index 46a5e9e5550cc3860d4e1fc69ba7a010a68ff33d..694a9258e98df3ffc203fa96d77fc72c90628a7c 100644
--- a/dbrepo-ui/utils/index.ts
+++ b/dbrepo-ui/utils/index.ts
@@ -1,7 +1,7 @@
-import {format} from 'date-fns'
 import moment from 'moment'
-import type {AxiosError} from 'axios'
-import type {H3Error} from "h3";
+import {AxiosError, type AxiosResponse, type InternalAxiosRequestConfig} from 'axios'
+import { format } from 'date-fns'
+import { getStatusText } from 'http-status-codes'
 
 
 export function notEmpty(str: string) {
@@ -25,24 +25,36 @@ export function notFile(files: [File[]]) {
   return files.length === 1
 }
 
-export function errorCodeKey(error: H3Error): any {
-  switch (error.statusCode) {
+export function makeError(status: number, code: string | null, message: string | null ): AxiosError {
+  const config: InternalAxiosRequestConfig = {}
+  const response: AxiosResponse = {
+    data: {},
+    status,
+    statusText: getStatusText(status).toUpperCase(),
+    config,
+    headers: {}
+  }
+  return new AxiosError(message, code, undefined, null, response)
+}
+
+export function errorCodeKey(error: AxiosError): any {
+  switch (error?.response?.status) {
     case 404:
       return {
         title: 'error.missing.title',
-        subtitle: 'ERR_NOT_FOUND',
+        subtitle: 'ERR_' + error?.response?.data?.status,
         text: 'error.missing.text'
       }
     case 403:
       return {
         title: 'error.permission.title',
-        subtitle: 'ERR_NOT_AUTHORIZED',
+        subtitle: 'ERR_' + error?.response?.data?.status,
         text: 'error.permission.text'
       }
     default:
       return {
         title: 'error.gone.title',
-        subtitle: 'ERR_GONE',
+        subtitle: 'ERR_' + error?.response?.data?.status,
         text: 'error.gone.text'
       }
   }