apollo
apollo copied to clipboard
Custom error handling not firing
Version
Reproduction link
Steps to reproduce
Add option to nuxt.config.js -> errorHandler: '~/plugins/apollo-error-handler.js', Create file and print error.
What is expected ?
It should print errors on the console
What is actually happening?
It doesn't print anything when an error happens.
Additional comments?
I'm trying to catch errors when the connection to the server is lost and there's a subscription ongoing. But I can't even catch and log when the server isn't connected and I try to run a query. It's like if the file in "errorHandler" option is ignored.
I'm seeing this too. Impossible to get access to the error object directly. It's locked as a string now, of this format Error: GraphQL error: {...}.
apollo: {
errorHandler: "~/plugins/apollo-error-handler.js",
clientConfigs: {
default: "~/plugins/apollo-config-default.js"
}
}
But error handler apollo-error-handler.js is this:
export default (
{ graphQLErrors, networkError, operation, forward },
nuxtContext
) => {
console.log("Global error handler")
console.log(graphQLErrors, networkError, operation, forward)
}
I'm hoping once this works, I can catch a network error and handle a token refresh call. If anyone has any tips on a better way to handle seamless token refresh I'd love to hear it.

Errors...
Would you mind explaining how did you set it up?
Would you mind explaining how did you set it up?
I'm trying to use the 'apollo' module on nuxt, but I have two problems. Whenever I try to make a query it returns the value in the SSR, and twice in the client

This query that I'm trying to access is limited, I give an apollo error with access denied. Breaking AI leaves this error more.
vue.runtime.esm.js?2b0e:619 [Vue warn]: The client-side rendered virtual DOM tree is not matching server-rendered content. This is likely caused by incorrect HTML markup, for example nesting block-level elements inside <p>, or missing <tbody>. Bailing hydration and performing full client-side render.

<script> import gql from 'graphql-tag' export default { name: 'Teste', apollo: { account: { query: gql { account { id login real_name email telefone zipcode create_time status availDt last_play cash mileage avatar capa pais roles } } , update(data) { console.log(data) return data.account }, deep: false, prefetch: true, fetchPolicy: 'network-only' } }, data() { return { account: null } } } </script>
Sorry for any typing mistakes, I am Brazilian and I will use the Google translator.
But then, you can use asyncData and call a query using the this function. $ Apollo.query (...) It works normally, so there are errors with then / catch.
Believe or solve problems in error handling in SSR,
@rospirski I think your errors are unrelated to the error handler.
I made a sandbox showing the error handler not working: https://codesandbox.io/s/apollo-broken-error-handler-499o7
Hi, try to add error handler to plugins section in your nuxt.config too. It works for me when using apollo module in component like you have in sandbox.
@dmitrijt9 Can you share your config? Weird you need to define it in 2 places.
@drewbaker I's weird for me either. Here it is:
require('dotenv').config()
module.exports = {
mode: 'universal',
/*
** Headers of the page
*/
head: {
title: process.env.npm_package_name || '',
meta: [
{ charset: 'utf-8' },
{ name: 'viewport', content: 'width=device-width, initial-scale=1' },
{ hid: 'description', name: 'description', content: process.env.npm_package_description || '' }
],
link: [
{ rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' }
]
},
/*
** Customize the progress-bar color
*/
loading: { color: '#fff' },
/*
** Global CSS
*/
css: [
'~/assets/css/tailwind.css',
'@fortawesome/fontawesome-svg-core/styles.css'
],
tailwindcss: {
cssPath: '~/assets/css/tailwind.css',
},
/*
** Plugins to load before mounting the App
*/
plugins: [
'~/plugins/fontawesome.js',
'~/plugins/apollo-error-handler.js'
],
/*
** Nuxt.js dev-modules
*/
buildModules: [
// Doc: https://github.com/nuxt-community/eslint-module
'@nuxtjs/eslint-module',
// Doc: https://github.com/nuxt-community/nuxt-tailwindcss
'@nuxtjs/tailwindcss',
// Doc: https://github.com/nuxt-community/dotenv-module
'@nuxtjs/dotenv',
],
// dotenv options
dotenv: {
path: '../../' // point to global .env file
},
eslint: {
fix: true
},
router: {
middleware: ['auth']
},
proxy: {
'/api': {
target: 'http://localhost:4000',
pathRewrite: {'^/api': '/'}
},
'/api/playground': {
target: 'http://localhost:4000/playground',
pathRewrite: {'^/api': '/'}
}
},
/*
** Nuxt.js modules
*/
modules: [
'@nuxtjs/apollo',
'@nuxtjs/proxy',
'@nuxtjs/toast',
[
'nuxt-i18n',
{
defaultLocale: 'en',
locales: [
{ code: 'cs', iso: 'cs-CZ', file: 'cs.json'},
{ code: 'en', iso: 'en-Us', file: 'en.json'}
],
lazy: true,
langDir: 'translations/',
parsePages: false,
pages: {
about: {
cs: '/o-aplikaci',
en: '/about'
},
app: {
cs: '/app',
en: '/app',
},
'app/dashboard': {
cs: '/app/nastenka',
en: '/app/dashboard'
},
'app/calendar': {
cs: '/app/kalendar',
en: '/app/calendar'
},
'app/tasks': {
cs: '/app/ukoly',
en: '/app/tasks'
},
'app/team': {
cs: '/app/tym',
en: '/app/team'
},
'app/discussion': {
cs: '/app/diskuze',
en: '/app/discussion'
},
}
}
]
],
// Apollo config
apollo: {
tokenName: 'apollo-token',
cookieAttributes: {
secure: process.env.ENV !== 'dev',
expires: 365,// cookie expiration 1 year
path: '/'
},
clientConfigs: {
default: {
httpEndpoint: 'http://localhost:4000',
browserHttpEndpoint: '/api'
}
},
errorHandler: '~/plugins/apollo-error-handler.js'
},
toast: {
position: 'top-right',
duration: 5000,
action: {
text: 'X',
onClick : (e, toastObject) => {
toastObject.goAway(0);
},
class: 'notification'
},
containerClass: 'theme-light',
className: 'notification'
},
/*
** Build configuration
*/
build: {
/*
** You can extend webpack config here
*/
extend (config, ctx) {
}
}
}
@rospirski I think your errors are unrelated to the error handler.
I made a sandbox showing the error handler not working: https://codesandbox.io/s/apollo-broken-error-handler-499o7
I did a minimal here If I access the link '/ test1' it works normally because there is no error Now if I access '/ teste2 /' as it generates an ApolloError in the API, this error simply appears on the console, I can treat it as you ordered, but even so it still generates the error.
Remembering that it is necessary to access the page and give an F5, the rendering needs to be on the Server, not just on the client side.


And as you can be the logs are always duplicated.
Github with the project I used. https://github.com/rospirski/Apoll-Nuxt-Problem
As a solution I am using nuxt's asyncData ... but no solution yet?
@drewbaker @rospirski So, I've mistaken previously. You don't have to mention apollo-error-handler in plugins in nuxt config, it's enough to write it in apollo config.
But I noticed that apollo-error-handler triggers only on client side... And it triggers only when using apollo smart query.
Which is quite weird and not sure, that this is correct. There is one positive thing about it, that you can immediately show some error notification to the user etc. But I still think it should be triggering on server.
@drewbaker @rospirski So, I've mistaken previously. You don't have to mention apollo-error-handler in plugins in nuxt config, it's enough to write it in apollo config.
But I noticed that apollo-error-handler triggers only on client side... And it triggers only when using apollo smart query.
Which is quite weird and not sure, that this is correct. There is one positive thing about it, that you can immediately show some error notification to the user etc. But I still think it should be triggering on server.
So, if I use nuxt's asyncData, I can use the context error, resize the page for the error layout. An alternative would be to use both. SmartQuery and AsyndData, however it would be two requests.
I'll look somewhere to avoid showing the error
a if(process.client)
@Akryum help pliz 👍
@rospirski thnaks! I can get the error handler to be used like you have it, but only in smart queries, not in mutations using this.$apollo.mutate(), then it will use the generic error handler (which makes it impossible to do things like "${error.details.field} input not provided" messages.
Is there no solution for catching 400 errors from Apollo? Even something as simple as an email validation on a mutation only throws a global error. As @drewbaker mentioned, the ability to read the body of error messages on a 400 would be ideal.
@drewbaker Hello, you can handle a token refresh call this way:
// nuxt.config.ts
'apollo': {
'clientConfigs': {
'default': '~/apollo/client-configs/default.ts',
},
},
// apollo/client-configs/default.ts
async function fetchNewAccessToken (ctx: Context): Promise<string | undefined> {
await ctx.store.dispatch('auth/fetchAuthToken');
return ctx.store.state.auth.authToken;
}
function errorHandlerLink (ctx: Context): any {
return ApolloErrorHandler({
isUnauthenticatedError (graphQLError: GraphQLError): boolean {
const { extensions } = graphQLError;
return extensions?.exception?.message === 'Unauthorized';
},
'fetchNewAccessToken': fetchNewAccessToken.bind(undefined, ctx),
'authorizationHeaderKey': 'X-MyService-Auth',
});
}
export default function DefaultConfig (ctx: Context): unknown {
return {
'link': ApolloLink.from([errorHandlerLink(ctx)]),
'httpEndpoint': ctx.env.GRAPHQL_URL,
};
}
// apollo/error-handler.ts
export default function ApolloErrorHandler ({
isUnauthenticatedError,
fetchNewAccessToken,
authorizationHeaderKey,
} : Options): any {
return onError(({
graphQLErrors,
networkError,
forward,
operation,
}) => {
if (graphQLErrors) {
for (const error of graphQLErrors) {
if (isUnauthenticatedError(error)) {
return new Observable(observer => {
fetchNewAccessToken()
.then(newAccessToken => {
if (!newAccessToken) {
throw new Error('Unable to fetch new access token');
}
operation.setContext(({ headers = {} }: any) => ({
'headers': {
...headers,
[authorizationHeaderKey]: newAccessToken || undefined,
},
}));
})
.then(() => {
const subscriber = {
'next': observer.next.bind(observer),
'error': observer.error.bind(observer),
'complete': observer.complete.bind(observer),
};
forward(operation).subscribe(subscriber);
})
.catch(fetchError => {
observer.error(fetchError);
});
});
}
}
} else if (networkError) {
// ...
}
});
}
See https://github.com/baleeds/apollo-link-refresh-token
@Akryum Is there no solution to this problem? How can we manage errors? Especially when we have 401 errors I have to redirect the user to the login page
Yes, same here... Some have found a workaround to be able to intercept the graphql errors?
Yes, same here... Some have found a workaround to be able to intercept the graphql errors?
hi I handled it using apollo-link-error in apollo-config.js source: https://v4.apollo.vuejs.org/guide-composable/error-handling.html#network-errors
Seems good but, how I can do that on nuxt?
Seems good but, how I can do that on nuxt?
Oh I see! using the client config... thanks
Yes, same here... Some have found a workaround to be able to intercept the graphql errors?
hi I handled it using apollo-link-error in apollo-config.js source: https://v4.apollo.vuejs.org/guide-composable/error-handling.html#network-errors
How did you manage to redirect to the login page? It tells me that "router is not defined" when i try to do a router.push
Yes, same here... Some have found a workaround to be able to intercept the graphql errors?
hi I handled it using apollo-link-error in apollo-config.js source: https://v4.apollo.vuejs.org/guide-composable/error-handling.html#network-errors
How did you manage to redirect to the login page? It tells me that "router is not defined" when i try to do a router.push
you most use redirect method
in plugins/apollo-config.js :
export default function ({ redirect }) { redirect('/auth/login') }
Yes, same here... Some have found a workaround to be able to intercept the graphql errors?
hi I handled it using apollo-link-error in apollo-config.js source: https://v4.apollo.vuejs.org/guide-composable/error-handling.html#network-errors
How did you manage to redirect to the login page? It tells me that "router is not defined" when i try to do a router.push
you most use redirect method in plugins/apollo-config.js :
export default function ({ redirect }) { redirect('/auth/login') }
Thanks!!!
@SebasEC96 move your code into the function before return
export default function ({ redirect }) {
const link = onError(({ graphQLErrors, networkError }) => {
if (graphQLErrors) {
graphQLErrors.map(({ message }) => {
if (`${message}` === 'Unauthenticated.') {
redirect('/login')
// Do Something
localStorage.setItem('logged', false)
}
})
}
if (networkError) {
console.log(`[Network error]: ${networkError}`)
}
})
return {
defaultHttpLink: false,
link: ApolloLink.from([link, createHttpLink({
credentials: 'include',
uri: 'http://localhost:8000/graphql',
fetch: (uri, options) => {
options.headers['X-XSRF-TOKEN'] = Cookies.get('XSRF-TOKEN')
return fetch(uri, options)
}
})]),
cache: new InMemoryCache()
}
}`
FYI for gave up on Apollo and switched to this, works way better with Nuxt in my opinion: https://github.com/Gomah/nuxt-graphql-request
@SebasEC96 move your code into the function before return
export default function ({ redirect }) { const link = onError(({ graphQLErrors, networkError }) => { if (graphQLErrors) { graphQLErrors.map(({ message }) => { if (`${message}` === 'Unauthenticated.') { redirect('/login') // Do Something localStorage.setItem('logged', false) } }) } if (networkError) { console.log(`[Network error]: ${networkError}`) } }) return { defaultHttpLink: false, link: ApolloLink.from([link, createHttpLink({ credentials: 'include', uri: 'http://localhost:8000/graphql', fetch: (uri, options) => { options.headers['X-XSRF-TOKEN'] = Cookies.get('XSRF-TOKEN') return fetch(uri, options) } })]), cache: new InMemoryCache() } }`
Yes, it took me a while to realize it, that's why I deleted the message, thanks!
FYI for gave up on Apollo and switched to this, works way better with Nuxt in my opinion: https://github.com/Gomah/nuxt-graphql-request
It depends on your needs, it does not use the cache among other things, but I will save it in case i need it at any time, thanks!
After finding this issue and searching through the source code of this library, vue-apollo and subscriptions-transport-ws, I was able to come up with a a way to handle token refreshes (only logging out in my example) and network errors from sockets and requests, on the server and the client. I was very close to taking @drewbaker's advice and switching libraries.
It's not super pretty and does duplicate some code in this library, but it shows how to completely customize the Apollo client. https://gist.github.com/KazW/2b5e4cb8f43566a69d3917ee7f30dbcc