{"record":{"id":"584815f4d87a530a","repo":"bytebase/bytebase","slug":"another-chat-is-already-using-a-page-changing-tool","errorCode":null,"errorMessage":"Another chat is already using a page-changing tool. Wait for it to finish, then retry this chat.","messagePattern":"Another chat is already using a page-changing tool\\. Wait for it to finish, then retry this chat\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"frontend/src/modules/agent/logic/tools/index.ts","lineNumber":385,"sourceCode":"\ninterface CreateToolExecutorOptions {\n  chatId?: string;\n  onNavigate?: () => void;\n}\n\nconst PAGE_MUTATION_TOOL_NAMES = new Set([\"navigate\", \"dom_action\"]);\nlet pageMutationChatId: string | null = null;\n\nconst withPageMutationLock = async <T>(\n  chatId: string | undefined,\n  toolName: string,\n  run: () => Promise<T>\n): Promise<T> => {\n  if (!PAGE_MUTATION_TOOL_NAMES.has(toolName) || !chatId) {\n    return run();\n  }\n  if (pageMutationChatId && pageMutationChatId !== chatId) {\n    throw new Error(\n      \"Another chat is already using a page-changing tool. Wait for it to finish, then retry this chat.\"\n    );\n  }\n\n  pageMutationChatId = chatId;\n  try {\n    return await run();\n  } finally {\n    if (pageMutationChatId === chatId) {\n      pageMutationChatId = null;\n    }\n  }\n};\n\nexport function createToolExecutor(\n  router: AppRouterInstance,\n  options: CreateToolExecutorOptions = {}\n): ToolExecutor {","sourceCodeStart":367,"sourceCodeEnd":403,"githubUrl":"https://github.com/bytebase/bytebase/blob/1870550677fe08f0d2a78c07acd27541464eb945/frontend/src/modules/agent/logic/tools/index.ts#L367-L403","documentation":"BatchGetUsers wraps a convertToUser failure as INTERNAL with 'failed to convert user' while building the response. The store lookup and name matching succeeded; converting a found store user into its protobuf representation (with IAM enrichment) failed.","triggerScenarios":"BatchGetUsers where one of the matched users has inconsistent IAM data, so convertToUser errors mid-loop.","commonSituations":"One user in the batch has an IAM role bound to a deleted project, or an unrecognized role after a version upgrade; corrupted policy JSON for that user.","solutions":["Find which user failed from server logs (the loop index/name identifies it).","Inspect that user's IAM role bindings for references to deleted projects or unknown roles.","Repair or remove the orphaned binding and retry the batch call.","If it started after an upgrade, confirm migrations completed cleanly."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"resp, err := client.BatchGetUsers(ctx, req)\nif connect.CodeOf(err) == connect.CodeInternal && strings.Contains(err.Error(), \"failed to convert user\") {\n\t// IAM data inconsistency for one member of the batch\n\treturn fallbackToIndividualLookups(ctx, client, names)\n}","preventionTips":["Cascade-delete IAM bindings with their owning project or role.","Audit IAM rows after upgrades for unknown role names.","Keep per-user conversion failures isolated by falling back to single lookups."],"tags":["iam","internal-error","batch-lookup"],"backgroundTag":"internal-invariant-violation","analyzedSha":"1870550677fe08f0d2a78c07acd27541464eb945","analyzedAt":"2026-09-06T21:16:13.665Z","contentChangedAt":"2026-09-06T21:16:13.665Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}