{"meta":{"title":"Крюк для обработки ошибок","intro":"onErrorOccurred Крюк вызывается, когда во время выполнения сессии возникают ошибки. Он используется для следующих задач:","product":"GitHub Copilot","breadcrumbs":[{"href":"/ru/copilot","title":"GitHub Copilot"},{"href":"/ru/copilot/how-tos","title":"Инструкции"},{"href":"/ru/copilot/how-tos/copilot-sdk","title":"Второй пилот SDK"},{"href":"/ru/copilot/how-tos/copilot-sdk/hooks","title":"Используйте крючки"},{"href":"/ru/copilot/how-tos/copilot-sdk/hooks/error-handling","title":"Обработка ошибок"}],"documentType":"article"},"body":"# Крюк для обработки ошибок\n\nonErrorOccurred Крюк вызывается, когда во время выполнения сессии возникают ошибки. Он используется для следующих задач:\n\n<!-- markdownlint-disable GHD046 GHD005 -->\n\n<!-- Suppressed: GHD046 (outdated release terminology), GHD005 (hardcoded data variable) -->\n\n* Реализовать пользовательский журнал ошибок\n* Паттерны ошибок трека\n* Предоставлять удобные сообщения об ошибках\n* Триггерные оповещения о критических ошибках\n\n## Сигнатура крюка\n\n<div class=\"ghd-codetabs\">\n<div class=\"ghd-codetab\" data-lang=\"typescript\" data-label=\"TypeScript\"><div class=\"ghd-codetab-fallback-label\" role=\"heading\" aria-level=\"3\">TypeScript</div>\n\n```typescript\ntype ErrorOccurredHandler = (\n  input: ErrorOccurredHookInput,\n  invocation: HookInvocation\n) => Promise<ErrorOccurredHookOutput | null | undefined>;\n```\n\n</div>\n\n<div class=\"ghd-codetab\" data-lang=\"python\" data-label=\"Python\"><div class=\"ghd-codetab-fallback-label\" role=\"heading\" aria-level=\"3\">Python</div>\n\n```python\nErrorOccurredHandler = Callable[\n    [ErrorOccurredHookInput, dict[str, str]],\n    Awaitable[ErrorOccurredHookOutput | None]\n]\n```\n\n</div>\n\n<div class=\"ghd-codetab\" data-lang=\"go\" data-label=\"Go\"><div class=\"ghd-codetab-fallback-label\" role=\"heading\" aria-level=\"3\">Go</div>\n\n```golang\ntype ErrorOccurredHandler func(\n    input ErrorOccurredHookInput,\n    invocation HookInvocation,\n) (*ErrorOccurredHookOutput, error)\n```\n\n</div>\n\n<div class=\"ghd-codetab\" data-lang=\"dotnet\" data-label=\".NET\"><div class=\"ghd-codetab-fallback-label\" role=\"heading\" aria-level=\"3\">.NET</div>\n\n```csharp\npublic delegate Task<ErrorOccurredHookOutput?> ErrorOccurredHandler(\n    ErrorOccurredHookInput input,\n    HookInvocation invocation);\n```\n\n</div>\n\n<div class=\"ghd-codetab\" data-lang=\"java\" data-label=\"Java\"><div class=\"ghd-codetab-fallback-label\" role=\"heading\" aria-level=\"3\">Java</div>\n\n<!-- docs-validate: skip -->\n\n```java\n// Note: Java SDK does not have an onErrorOccurred hook.\n// Use EventErrorPolicy and EventErrorHandler instead:\n//\n// session.setEventErrorPolicy(EventErrorPolicy.SUPPRESS_AND_LOG_ERRORS);\n// session.setEventErrorHandler((event, ex) -> {\n//     System.err.println(\"Error in \" + event.getType() + \": \" + ex.getMessage());\n// });\n//\n// See the \"Basic Error Logging\" example below for a complete snippet.\n```\n\n</div>\n\n</div>\n\n## Input\n\n| Поле           | Тип     | Description                                                                              |\n| -------------- | ------- | ---------------------------------------------------------------------------------------- |\n| `timestamp`    | Номер   | Временная метка Unix в момент возникшей ошибки                                           |\n| `cwd`          | струна  | Текущий рабочий справочник                                                               |\n| `error`        | струна  | Сообщение об ошибке                                                                      |\n| `errorContext` | струна  | Где произошла ошибка: `\"model_call\"`, `\"tool_execution\"`, `\"system\"`, или `\"user_input\"` |\n| `recoverable`  | boolean | Можно ли потенциально восстановить ошибку из                                             |\n\n## Output\n\nВозврат `null` или `undefined` использование обработки ошибок по умолчанию. В противном случае вернём объект с:\n\n| Поле               | Тип     | Description                                                 |\n| ------------------ | ------- | ----------------------------------------------------------- |\n| `suppressOutput`   | boolean | Если это верно, не показывайте ошибку пользователю          |\n| `errorHandling`    | струна  | Как справиться: `\"retry\"`, `\"skip\"`, или `\"abort\"`          |\n| `retryCount`       | Номер   | Количество повторных попыток (если errorHandling )`\"retry\"` |\n| `userNotification` | струна  | Пользовательское сообщение для показа пользователю          |\n\n## Примеры\n\n### Базовое ведение ошибок\n\n<div class=\"ghd-codetabs\">\n<div class=\"ghd-codetab\" data-lang=\"typescript\" data-label=\"TypeScript\"><div class=\"ghd-codetab-fallback-label\" role=\"heading\" aria-level=\"3\">TypeScript</div>\n\n```typescript\nconst session = await client.createSession({\n  hooks: {\n    onErrorOccurred: async (input, invocation) => {\n      console.error(`[${invocation.sessionId}] Error: ${input.error}`);\n      console.error(`  Context: ${input.errorContext}`);\n      console.error(`  Recoverable: ${input.recoverable}`);\n      return null;\n    },\n  },\n});\n```\n\n</div>\n\n<div class=\"ghd-codetab\" data-lang=\"python\" data-label=\"Python\"><div class=\"ghd-codetab-fallback-label\" role=\"heading\" aria-level=\"3\">Python</div>\n\n```python\nfrom copilot.session import PermissionHandler\n\nasync def on_error_occurred(input_data, invocation):\n    print(f\"[{invocation['session_id']}] Error: {input_data['error']}\")\n    print(f\"  Context: {input_data['errorContext']}\")\n    print(f\"  Recoverable: {input_data['recoverable']}\")\n    return None\n\nsession = await client.create_session(on_permission_request=PermissionHandler.approve_all, hooks={\"on_error_occurred\": on_error_occurred})\n```\n\n</div>\n\n<div class=\"ghd-codetab\" data-lang=\"go\" data-label=\"Go\"><div class=\"ghd-codetab-fallback-label\" role=\"heading\" aria-level=\"3\">Go</div>\n\n```golang\nsession, _ := client.CreateSession(context.Background(), &copilot.SessionConfig{\n    Hooks: &copilot.SessionHooks{\n        OnErrorOccurred: func(input copilot.ErrorOccurredHookInput, inv copilot.HookInvocation) (*copilot.ErrorOccurredHookOutput, error) {\n            fmt.Printf(\"[%s] Error: %s\\n\", inv.SessionID, input.Error)\n            fmt.Printf(\"  Context: %s\\n\", input.ErrorContext)\n            fmt.Printf(\"  Recoverable: %v\\n\", input.Recoverable)\n            return nil, nil\n        },\n    },\n})\n```\n\n</div>\n\n<div class=\"ghd-codetab\" data-lang=\"dotnet\" data-label=\".NET\"><div class=\"ghd-codetab-fallback-label\" role=\"heading\" aria-level=\"3\">.NET</div>\n\n```csharp\nvar session = await client.CreateSessionAsync(new SessionConfig\n{\n    Hooks = new SessionHooks\n    {\n        OnErrorOccurred = (input, invocation) =>\n        {\n            Console.Error.WriteLine($\"[{invocation.SessionId}] Error: {input.Error}\");\n            Console.Error.WriteLine($\"  Context: {input.ErrorContext}\");\n            Console.Error.WriteLine($\"  Recoverable: {input.Recoverable}\");\n            return Task.FromResult<ErrorOccurredHookOutput?>(null);\n        },\n    },\n});\n```\n\n</div>\n\n<div class=\"ghd-codetab\" data-lang=\"java\" data-label=\"Java\"><div class=\"ghd-codetab-fallback-label\" role=\"heading\" aria-level=\"3\">Java</div>\n\n<!-- docs-validate: skip -->\n\n```java\nimport com.github.copilot.*;\nimport com.github.copilot.rpc.*;\n\n// Note: Java SDK does not have an onErrorOccurred hook.\n// Use EventErrorPolicy and EventErrorHandler instead:\n\nvar session = client.createSession(\n    new SessionConfig()\n        .setOnPermissionRequest(PermissionHandler.APPROVE_ALL)\n).get();\n\nsession.setEventErrorPolicy(EventErrorPolicy.SUPPRESS_AND_LOG_ERRORS);\nsession.setEventErrorHandler((event, ex) -> {\n    System.err.println(\"[\" + session.getSessionId() + \"] Error: \" + ex.getMessage());\n    System.err.println(\"  Event: \" + event.getType());\n});\n```\n\n</div>\n\n</div>\n\n### Отправьте ошибки в сервис мониторинга\n\n```typescript\nimport { captureException } from \"@sentry/node\"; // or your monitoring service\n\nconst session = await client.createSession({\n  hooks: {\n    onErrorOccurred: async (input, invocation) => {\n      captureException(new Error(input.error), {\n        tags: {\n          sessionId: invocation.sessionId,\n          errorContext: input.errorContext,\n        },\n        extra: {\n          error: input.error,\n          recoverable: input.recoverable,\n          cwd: input.cwd,\n        },\n      });\n      \n      return null;\n    },\n  },\n});\n```\n\n### Понятные пользователю сообщения об ошибках\n\n```typescript\nconst ERROR_MESSAGES: Record<string, string> = {\n  \"model_call\": \"There was an issue communicating with the AI model. Please try again.\",\n  \"tool_execution\": \"A tool failed to execute. Please check your inputs and try again.\",\n  \"system\": \"A system error occurred. Please try again later.\",\n  \"user_input\": \"There was an issue with your input. Please check and try again.\",\n};\n\nconst session = await client.createSession({\n  hooks: {\n    onErrorOccurred: async (input) => {\n      const friendlyMessage = ERROR_MESSAGES[input.errorContext];\n      \n      if (friendlyMessage) {\n        return {\n          userNotification: friendlyMessage,\n        };\n      }\n      \n      return null;\n    },\n  },\n});\n```\n\n### Подавление некритических ошибок\n\n```typescript\nconst session = await client.createSession({\n  hooks: {\n    onErrorOccurred: async (input) => {\n      // Suppress tool execution errors that are recoverable\n      if (input.errorContext === \"tool_execution\" && input.recoverable) {\n        console.log(`Suppressed recoverable error: ${input.error}`);\n        return { suppressOutput: true };\n      }\n      return null;\n    },\n  },\n});\n```\n\n### Добавить контекст восстановления\n\n```typescript\nconst session = await client.createSession({\n  hooks: {\n    onErrorOccurred: async (input) => {\n      if (input.errorContext === \"tool_execution\") {\n        return {\n          userNotification: `\nThe tool failed. Here are some recovery suggestions:\n- Check if required dependencies are installed\n- Verify file paths are correct\n- Try a simpler approach\n          `.trim(),\n        };\n      }\n      \n      if (input.errorContext === \"model_call\" && input.error.includes(\"rate\")) {\n        return {\n          errorHandling: \"retry\",\n          retryCount: 3,\n          userNotification: \"Rate limit hit. Retrying...\",\n        };\n      }\n      \n      return null;\n    },\n  },\n});\n```\n\n### Паттерны ошибок трека\n\n```typescript\ninterface ErrorStats {\n  count: number;\n  lastOccurred: number;\n  contexts: string[];\n}\n\nconst errorStats = new Map<string, ErrorStats>();\n\nconst session = await client.createSession({\n  hooks: {\n    onErrorOccurred: async (input, invocation) => {\n      const key = `${input.errorContext}:${input.error.substring(0, 50)}`;\n      \n      const existing = errorStats.get(key) || {\n        count: 0,\n        lastOccurred: 0,\n        contexts: [],\n      };\n      \n      existing.count++;\n      existing.lastOccurred = input.timestamp;\n      existing.contexts.push(invocation.sessionId);\n      \n      errorStats.set(key, existing);\n      \n      // Alert if error is recurring\n      if (existing.count >= 5) {\n        console.warn(`Recurring error detected: ${key} (${existing.count} times)`);\n      }\n      \n      return null;\n    },\n  },\n});\n```\n\n### Предупреждение о критических ошибках\n\n```typescript\nconst CRITICAL_CONTEXTS = [\"system\", \"model_call\"];\n\nconst session = await client.createSession({\n  hooks: {\n    onErrorOccurred: async (input, invocation) => {\n      if (CRITICAL_CONTEXTS.includes(input.errorContext) && !input.recoverable) {\n        await sendAlert({\n          level: \"critical\",\n          message: `Critical error in session ${invocation.sessionId}`,\n          error: input.error,\n          context: input.errorContext,\n          timestamp: new Date(input.timestamp).toISOString(),\n        });\n      }\n      \n      return null;\n    },\n  },\n});\n```\n\n### Комбинируйте с другими зацепками для контекста\n\n```typescript\nconst sessionContext = new Map<string, { lastTool?: string; lastPrompt?: string }>();\n\nconst session = await client.createSession({\n  hooks: {\n    onPreToolUse: async (input, invocation) => {\n      const ctx = sessionContext.get(invocation.sessionId) || {};\n      ctx.lastTool = input.toolName;\n      sessionContext.set(invocation.sessionId, ctx);\n      return { permissionDecision: \"allow\" };\n    },\n    \n    onUserPromptSubmitted: async (input, invocation) => {\n      const ctx = sessionContext.get(invocation.sessionId) || {};\n      ctx.lastPrompt = input.prompt.substring(0, 100);\n      sessionContext.set(invocation.sessionId, ctx);\n      return null;\n    },\n    \n    onErrorOccurred: async (input, invocation) => {\n      const ctx = sessionContext.get(invocation.sessionId);\n      \n      console.error(`Error in session ${invocation.sessionId}:`);\n      console.error(`  Error: ${input.error}`);\n      console.error(`  Context: ${input.errorContext}`);\n      if (ctx?.lastTool) {\n        console.error(`  Last tool: ${ctx.lastTool}`);\n      }\n      if (ctx?.lastPrompt) {\n        console.error(`  Last prompt: ${ctx.lastPrompt}...`);\n      }\n      \n      return null;\n    },\n  },\n});\n```\n\n## Лучшие практики\n\n1. **Всегда фиксируйте ошибки** — даже если вы их подавляете от пользователей, ведите логи для отладки.\n\n2. **Категоризировать ошибки** — использовать `errorType` для правильной обработки различных ошибок.\n\n3. **Не принимайте критические ошибки** — подавляйте только те ошибки, в которых уверены, что они не критичные.\n\n4. **Держите крючки быстрыми** — обработка ошибок не должна замедлять восстановление.\n\n5. **Предоставьте полезный контекст** — когда возникают ошибки, `additionalContext` это может помочь модели восстановиться.\n\n6. **Отслеживайте шаблоны ошибок** — отслеживайте повторяющиеся ошибки для выявления системных проблем.\n\n## См. также\n\n* [Используйте крючки](/ru/copilot/how-tos/copilot-sdk/hooks)\n* [Крючки жизненного цикла сессии](/ru/copilot/how-tos/copilot-sdk/hooks/session-lifecycle)\n* [Руководство по отладке](/ru/copilot/how-tos/copilot-sdk/troubleshooting/debugging)"}