{"record":{"id":"ace3b2db5d35922d","repo":"toeverything/AFFiNE","slug":"action-forbidden","errorCode":"action_forbidden","errorMessage":"You are not allowed to perform this action.","messagePattern":"You are not allowed to perform this action\\.","errorType":"http","errorClass":"ActionForbidden","httpStatus":403,"severity":"warning","filePath":"packages/backend/server/src/base/error/index.ts","lineNumber":16,"sourceCode":"import { writeFileSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nimport { Logger, Module, OnModuleInit } from '@nestjs/common';\nimport { Args, Query, Resolver } from '@nestjs/graphql';\n\nimport { generateUserFriendlyErrors } from './def';\nimport { ActionForbidden, ErrorDataUnionType, ErrorNames } from './errors.gen';\n\n@Resolver(() => ErrorDataUnionType)\nclass ErrorResolver {\n  // only exists for type registering\n  @Query(() => ErrorDataUnionType)\n  error(@Args({ name: 'name', type: () => ErrorNames }) _name: ErrorNames) {\n    throw new ActionForbidden();\n  }\n}\n\n@Module({\n  providers: [ErrorResolver],\n})\nexport class ErrorModule implements OnModuleInit {\n  logger = new Logger('ErrorModule');\n  onModuleInit() {\n    if (!env.dev) {\n      return;\n    }\n    this.logger.log('Generating UserFriendlyError classes');\n    const def = generateUserFriendlyErrors();\n\n    writeFileSync(\n      join(fileURLToPath(import.meta.url), '../errors.gen.ts'),\n      def","sourceCodeStart":1,"sourceCodeEnd":34,"githubUrl":"https://github.com/toeverything/AFFiNE/blob/26c515e050211269e911f7d9cfe162a26c83ed98/packages/backend/server/src/base/error/index.ts#L1-L34","documentation":"This ActionForbidden error (HTTP 403) is thrown by the ErrorResolver's placeholder GraphQL 'error' query, which exists solely to register the ErrorDataUnionType in the GraphQL schema. The query always throws ActionForbidden — it is not a real endpoint and should never be called by clients. Hitting it means a client is querying the 'error' field directly, which is not a valid operation.","triggerScenarios":"A GraphQL client executing a query against the 'error' field (e.g. query { error(name: ...) { ... } }). This field exists only for schema type registration and is not a functional API. Automated GraphQL introspection tools or fuzzers that query every field may trigger it.","commonSituations":"GraphQL exploration tools (Apollo Studio, GraphiQL auto-complete) that query the error field during schema exploration. Misconfigured client code that references the error union type as a query. Security scanners or fuzzers probing all GraphQL endpoints.","solutions":["Do not query the 'error' GraphQL field — it is a type-registration placeholder, not a real endpoint.","Review client GraphQL queries and remove any references to the 'error' query field.","If you see this in logs from automated tools, add the 'error' field to the tool's ignore/exclude list."],"exampleFix":"// before (GraphQL query)\nquery { error(name: BAD_REQUEST) { ... } } // always throws ActionForbidden\n\n// after\n// Remove the query entirely; this field is not a real API endpoint.","handlingStrategy":"validation","validationCode":"// Do not query the 'error' GraphQL field.\n// It exists only for schema type registration.\n// Before sending a query, verify the field is a real API endpoint:\nconst realQueries = ['user', 'workspace', 'doc'];\nif (!realQueries.includes(queryName)) {\n  console.warn(`'${queryName}' is not a valid query field.`);\n}","typeGuard":null,"tryCatchPattern":"try {\n  const result = await client.query({ query: MY_QUERY });\n} catch (e) {\n  if (e.message?.includes('action_forbidden')) {\n    // likely queried the placeholder 'error' field; review the query\n  }\n}","preventionTips":["Never reference the 'error' query field in client code.","Review GraphQL queries generated by auto-complete tools.","Exclude internal/placeholder fields from GraphQL fuzzing tools."],"tags":["graphql","affine-backend","error-handling","type-registration","forbidden"],"backgroundTag":null,"analyzedSha":"26c515e050211269e911f7d9cfe162a26c83ed98","analyzedAt":"2026-08-12T13:15:16.447Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}