{"record":{"id":"99e1224299b82f5c","repo":"toeverything/AFFiNE","slug":"internal-server-error","errorCode":"internal_server_error","errorMessage":"An internal error occurred.","messagePattern":"An internal error occurred\\.","errorType":"exception","errorClass":"InternalServerError","httpStatus":500,"severity":"critical","filePath":"packages/backend/server/src/core/permission/service.ts","lineNumber":81,"sourceCode":"    private readonly sqlPredicate = new PermissionSqlPredicateBuilder(),\n    @Optional()\n    private readonly workspacePolicy?: WorkspacePolicyService\n  ) {}\n\n  docReadableSqlPredicate(input: {\n    userId: string;\n    workspaceId: string;\n    action: DocAction;\n    docIdColumn?: Prisma.Sql;\n  }) {\n    return this.sqlPredicate.docReadableSql(input);\n  }\n\n  evaluate(input: PermissionEvaluationInputV1) {\n    try {\n      return evaluatePermissionV1(input);\n    } catch (error) {\n      throw new InternalServerError(\n        error instanceof Error ? error.message : undefined\n      );\n    }\n  }\n\n  async workspacePermissions(input: {\n    userId?: string;\n    workspaceId: string;\n    actions: PermissionWorkspaceAction[];\n    allowLocal?: boolean;\n  }) {\n    const output = await this.evaluateLoaded({\n      userId: input.userId,\n      workspaceId: input.workspaceId,\n      workspaceActions: input.actions,\n      allowLocal: input.allowLocal,\n    });\n    return {","sourceCodeStart":63,"sourceCodeEnd":99,"githubUrl":"https://github.com/toeverything/AFFiNE/blob/26c515e050211269e911f7d9cfe162a26c83ed98/packages/backend/server/src/core/permission/service.ts#L63-L99","documentation":"InternalServerError (code=internal_server_error) thrown by PermissionService.evaluate when the native evaluatePermissionV1 call throws. evaluatePermissionV1 delegates to a native (Rust/N-API) module; any panic/type mismatch/missing field in the input surfaces here, wrapped so the raw native message becomes the error's message. This is a true 500 — the inputs were structurally invalid for the evaluator or the native module is broken.","triggerScenarios":"Passing a PermissionEvaluationInputV1 with an unexpected role/action value, a missing docs array entry, malformed decision objects, or a shape the native evaluator doesn't recognize. Also fires if the native module failed to load or panicked on a specific input.","commonSituations":"A new permission role/action added to TS types but not to the native evaluator (version skew between native build and TS). Bad data from the DB feeding into the evaluator (null where a struct is expected). Native module built against a different schema. Memory/panic in the native lib under a specific input.","solutions":["Read the wrapped error.message — it carries the native module's complaint (often a field name or enum value).","Confirm the native module version matches the TS schema (rebuild/reinstall native bindings after schema changes).","Log the full input (with secrets redacted) when this fires so you can reproduce the failing evaluation shape.","Add a TS-level validator (zod/io-ts) in front of evaluatePermissionV1 to catch malformed inputs before they hit native code.","If isolated to one user/doc, inspect their role/decision rows for nulls or unknown enum values."],"exampleFix":"// before\ntry {\n  return evaluatePermissionV1(input);\n} catch (error) {\n  throw new InternalServerError(error instanceof Error ? error.message : undefined);\n}\n\n// after — validate input shape before native call, log structured context\nevaluate(input: PermissionEvaluationInputV1) {\n  const parsed = PermissionEvaluationInputV1Schema.safeParse(input);\n  if (!parsed.success) {\n    throw new BadRequest(`Invalid permission input: ${parsed.error.message}`);\n  }\n  try {\n    return evaluatePermissionV1(parsed.data);\n  } catch (error) {\n    this.logger.error('native permission evaluation failed', { input, error });\n    throw new InternalServerError(error instanceof Error ? error.message : undefined);\n  }\n}","handlingStrategy":"try-catch","validationCode":"import { z } from 'zod';\n// Define a schema matching PermissionEvaluationInputV1 and parse before native call\nconst InputSchema = z.object({\n  userId: z.string(),\n  workspaceId: z.string(),\n  action: z.string(),\n  docs: z.array(z.object({\n    docId: z.string(),\n    effectiveRole: z.string().optional(),\n    decisions: z.array(z.any()),\n  })),\n});\nfunction safeEvaluate(input: unknown) {\n  const parsed = InputSchema.safeParse(input);\n  if (!parsed.success) throw new Error(`Bad permission input: ${parsed.error.message}`);\n  return evaluatePermissionV1(parsed.data);\n}","typeGuard":"function isPermissionInternalError(e: unknown): boolean {\n  return e instanceof Error && (e as any).code === 'internal_server_error';\n}","tryCatchPattern":"try {\n  return permissionService.evaluate(input);\n} catch (e) {\n  if (isPermissionInternalError(e)) {\n    logger.error('permission eval failed', { input, cause: e.message });\n    // fail closed: deny rather than allow on evaluator failure\n    return { allowed: false, reason: 'evaluator-error' };\n  }\n  throw e;\n}","preventionTips":["Keep native module and TS schema versions in lockstep; rebuild native bindings after schema changes.","Validate input shape with zod/io-ts before hitting native code.","Fail closed (deny) on evaluator errors — never grant on uncertainty.","Log the full input (redacted) when this fires to enable reproduction.","Audit role/decision rows for nulls or unknown enum values feeding the evaluator."],"tags":["permission","native-module","internal-error","version-skew","authorization"],"backgroundTag":null,"analyzedSha":"26c515e050211269e911f7d9cfe162a26c83ed98","analyzedAt":"2026-08-12T13:15:16.447Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}