MeWrite Docs

ApolloServerError: Unexpected error processing request

Apollo Serverでリクエスト処理中にエラーが発生した場合の対処法

概要

Apollo Serverでリゾルバー実行中やリクエスト処理中に予期しないエラーが発生した場合のエラーです。

エラーメッセージ

1
2
3
4
5
6
7
8
{
  "errors": [{
    "message": "Unexpected error processing request",
    "extensions": {
      "code": "INTERNAL_SERVER_ERROR"
    }
  }]
}
ApolloServerErrorCode.INTERNAL_SERVER_ERROR

解決策

1. カスタムエラークラスを使用

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
import { GraphQLError } from 'graphql'

// カスタムエラーを定義
export class AuthenticationError extends GraphQLError {
  constructor(message: string) {
    super(message, {
      extensions: {
        code: 'UNAUTHENTICATED',
        http: { status: 401 },
      },
    })
  }
}

export class ForbiddenError extends GraphQLError {
  constructor(message: string) {
    super(message, {
      extensions: {
        code: 'FORBIDDEN',
        http: { status: 403 },
      },
    })
  }
}

// リゾルバーで使用
const resolvers = {
  Query: {
    secretData: (_, __, context) => {
      if (!context.user) {
        throw new AuthenticationError('Must be logged in')
      }
      if (!context.user.isAdmin) {
        throw new ForbiddenError('Admin access required')
      }
      return getSecretData()
    }
  }
}

2. エラーフォーマッター

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
import { ApolloServer } from '@apollo/server'
import { unwrapResolverError } from '@apollo/server/errors'

const server = new ApolloServer({
  typeDefs,
  resolvers,
  formatError: (formattedError, error) => {
    const originalError = unwrapResolverError(error)

    // 本番環境ではスタックトレースを隠す
    if (process.env.NODE_ENV === 'production') {
      delete formattedError.extensions?.stacktrace
    }

    // バリデーションエラーをカスタマイズ
    if (formattedError.extensions?.code === 'BAD_USER_INPUT') {
      return {
        ...formattedError,
        message: 'Invalid input provided',
      }
    }

    // 予期しないエラーをログ
    if (formattedError.extensions?.code === 'INTERNAL_SERVER_ERROR') {
      console.error('Unexpected error:', originalError)
    }

    return formattedError
  },
})

3. プラグインでエラーハンドリング

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
const errorLoggingPlugin = {
  async requestDidStart() {
    return {
      async didEncounterErrors({ errors, contextValue }) {
        for (const error of errors) {
          // Sentryなどに送信
          console.error('GraphQL Error:', {
            message: error.message,
            path: error.path,
            extensions: error.extensions,
          })
        }
      },
    }
  },
}

const server = new ApolloServer({
  typeDefs,
  resolvers,
  plugins: [errorLoggingPlugin],
})

4. リゾルバーでのtry-catch

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
const resolvers = {
  Query: {
    user: async (_, { id }) => {
      try {
        const user = await prisma.user.findUnique({
          where: { id },
        })

        if (!user) {
          throw new GraphQLError('User not found', {
            extensions: { code: 'NOT_FOUND' },
          })
        }

        return user
      } catch (error) {
        if (error instanceof GraphQLError) {
          throw error
        }
        // 予期しないエラー
        console.error('Database error:', error)
        throw new GraphQLError('Failed to fetch user', {
          extensions: { code: 'DATABASE_ERROR' },
        })
      }
    },
  },
}

5. 部分的なエラーレスポンス

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
// nullableなフィールドは部分的に成功可能
type Query {
  users: [User]  # エラー時は全体が失敗
  user(id: ID!): User  # nullableなので部分的に成功
}

// リゾルバー
const resolvers = {
  User: {
    // このフィールドがエラーでも他のフィールドは返る
    posts: async (user) => {
      try {
        return await fetchPosts(user.id)
      } catch (error) {
        return null  // 部分的な失敗
      }
    },
  },
}

6. Apollo Studio連携

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
import { ApolloServer } from '@apollo/server'
import { ApolloServerPluginUsageReporting } from '@apollo/server/plugin/usageReporting'

const server = new ApolloServer({
  typeDefs,
  resolvers,
  plugins: [
    ApolloServerPluginUsageReporting({
      sendErrors: { unmodified: true },
    }),
  ],
})

関連エラー

関連エラー

GraphQL の他のエラー

最終更新: 2025-12-22