Error Reporting
The IntelliJ Platform can detect many errors caused by plugin code and attribute them to the responsible plugin. Plugin authors can integrate with that flow in two different ways:
ErrorReportSubmitterhandles the user-facing reporting flow from the IDE Fatal Errors UI.ErrorReportSinkreceives automatic background reports about unhandled exceptions and UI freezes attributed to the plugin.
These APIs complement each other. ErrorReportSubmitter is the user-facing reporting API. It is triggered when the user chooses to submit a report from the IDE UI, so the user is explicitly involved in the process. It is typically used for issue tracker integration, custom backend submission, privacy notices, and account-aware reporting. The submitter receives IdeaLoggingEvent instances together with the user comment, any included attachments, and a callback used to complete the submission flow.
ErrorReportSink is the automatic background reporting API. It is triggered when the platform automatically forwards a plugin-attributed exception or freeze, so no user action is required. The sink receives either UnhandledExceptionReport or UnhandledFreezeReport, which makes it suitable for observability scenarios even when the user never clicks a reporting action.
Manual Reporting
JetBrains Marketplace Exception Analyzer
If the plugin is published on JetBrains Marketplace and the built-in reporting flow is sufficient, this is the simplest supported setup.
Register JetBrainsMarketplaceErrorReportSubmitter as an implementation of the com.intellij.errorHandler extension point in plugin.xml:
This approach requires no custom ErrorReportSubmitter implementation in the plugin. The IDE uses the built-in submitter to send reports to the backend provided by JetBrains.
See JetBrains Exception Analyzer for setup details and current product-specific behavior.
Custom Implementation of ErrorReportSubmitter
Use a custom submitter when the plugin needs control over the backend, payload, privacy notice, or the post-submission workflow.
Register the submitter in plugin.xml:
The public contract is defined by ErrorReportSubmitter. Reports are delivered as IdeaLoggingEvent instances, and the final result is reported back to the IDE using SubmittedReportInfo.
Where:
getReportActionText()defines the text shown on the report button in the reporting UIgetPrivacyNoticeText()must explain to users what data is sent and how it is usedsubmit()performs the actual submission
The submit() method receives the IdeaLoggingEvent data selected for the report:
events -
IdeaLoggingEventinstances give access to the core report data, such as theThrowable, message text, and attachments included in the report.additionalInfo- the free-form text entered by the user in the comment box asparentComponent- for any necessary interactionconsumer- callback that must receive the finalSubmittedReportInfo. This is the main integration point for building a custom payload for an issue tracker or backend service.
If submit() returns true, the submitter is declaring that the submission has started and the callback will be completed later. The callback must eventually receive a SubmittedReportInfo with the proper SubmissionStatus:
NEW_ISSUE- if the issue has been successfully filedDUPLICATE- if the issue is actually a duplicate of the existing oneFAILED- if the submission failed
If submission cannot even start, submit() must return false.
Threading and Coroutines
ErrorReportSubmitter.submit() should return quickly and avoid expensive blocking work as it runs on the EDT. Therefore, the general threading rules from Threading Model apply here as well. That means, operations on EDT must be as fast as possible to avoid UI freezes, while network, file, and other expensive operations belong on background threads.
For plugins targeting 2024.1+, Kotlin coroutines are the recommended approach for asynchronous work.
To keep submit() lightweight, a typical implementation first extracts the information needed from the incoming events, then starts the expensive work in the background, returns true, and finally completes the callback when submission finishes.
When using coroutines, prefer a service scope for submission work. Use Dispatchers.IO for network and file I/O.
This pattern keeps the reporting UI responsive while still integrating cleanly with the IDE callback contract.
Also, do not perform long-running non-cancellable read actions while collecting data for a report. Long-running read actions on background threads can block write actions and cause UI freezes. If additional project or PSI data is needed for a report, keep access short and use the modern threading and coroutine APIs described in Accessing Data and Launching Coroutines.
Automatic Reporting with ErrorReportSink
ErrorReportSink is an experimental API for automatic background reporting.
Register it via the com.intellij.errorReportSink extension point in plugin.xml:
Example:
ErrorReportSink currently delivers two report types:
UnhandledExceptionReportcontains the exception class and stack traceUnhandledFreezeReportcontains a message, the freeze duration, attachments, and thread dumps
ErrorReportSink is intended for plugin observability, not guaranteed report delivery and at most 10,000 exception reports per plugin per IDE session are forwarded. Note, that the platform does not deduplicate or debounce repeated exceptions, and exception reports contain less information than user-submitted reports.
The current platform implementation delivers sink reports asynchronously on a background dispatcher. Plugins should still keep sink processing short, deduplicate repeated failures, and rate-limit any backend traffic on their side.
Attachments and Freeze Reports
An exception report is often centered around a Throwable and its stack trace. However, you can provide additional context for such reports and log exceptions with attachments when useful:
Those attachments may later appear in the reporting UI and become part of the report delivered to the plugin's submitter.
Freeze reports are different from ordinary exception reports because they describe a stalled UI and usually need more evidence to explain what the IDE was waiting for. Therefore, when the platform records a plugin-attributed UI freeze, the report may contain one or more thread dumps and additional attachments collected during freeze reporting.
For ErrorReportSubmitter, those artifacts may appear as attachments in the IdeaLoggingEvent. For ErrorReportSink, they are represented explicitly by UnhandledFreezeReport.attachments and UnhandledFreezeReport.threadDumps.
Freeze reports are often caused by lock contention, blocking I/O, or long-running work that prevents EDT from progressing. In these cases, a simple exception stack trace is not enough and thread dumps plus freeze-specific attachments help answer:
what EDT was waiting for
which thread was holding the relevant lock
whether the plugin was doing background work that blocked a write action
whether the stall was transient, repeated, or part of a larger problem.
This is why freeze reports are usually much more diagnostically valuable than a plain stack trace.
Choosing Between the APIs
Use ErrorReportSubmitter when:
the user should explicitly submit the report
the plugin needs the user comment
a custom privacy notice or account-aware reporting is required
the backend expects a richer user-facing reporting flow
Use ErrorReportSink when:
the plugin should observe failures even if the user does nothing
the goal is telemetry, counting, alerting, or sending reports to your backend when possible, without guaranteeing delivery
automatic freeze visibility is important
Use both APIs when the plugin needs background observability during normal usage and also a richer user-driven reporting path for manual submission.
Example Implementations
ITNReporter A full production implementation that submits fatal error reports, shows progress and notifications, and completes the
SubmittedReportInfocallback.UnhandledReportSinkServiceTest.TestSinkA tiny sink used in tests that simply receives an UnhandledErrorReport in submit(report) and stores it for verification.Third party tutorial for error reporting using Sentry