Is it just me - o r if you open an unresolved issue/report the details of it display only a loading rectangle? I see date, IDE, OS - but no trace or anything that would actually help me make sense of what’s wrong.
Bumping this topic as Exceptions reported in the marketplace still show no stack trace for my MicroPython Tools plugin. All I see is the title, dates, IDE, Report + some numerical ID. And below it all an endlessly loading rectangle, which I presume is supposed to display a stack trace or something for me to actually be able to debug the reported exception.
Hello,
I have escalated this to the JetBrains Marketplace team to investigate.
Any update on this? I just never see more than the details in the left panel and the title. No actual exception/stack trace to work with.
Anyone else seeing this too? @jonathanlermitage.1 ?
Unsure if it is just my account or my browser etc.
Might just be new entries then..
I’m on macOS, but I tried with Brave and Safari to get the same behavior.
Sidenote: I’m curious as to what made you stop using it, do you have a more capable custom solution or was there something else?
The Marketplace’s exception tab is lacking important features (I submitted feature requests, without a great success). I preferred to implement my own exception reporter. It creates GitHub issues with the stacktrace, and the OS, IDE and plugin versions. Users can provide more information and I can discuss with them. Feedback is very important. Finally, I think you know how GitHub issues work: you can filter them, add badges, etc.
So, I simply think this is better for me and for my customers.
That makes sense… I thought the built-in exception handler might be better because it is lower effort (user is prompted by an in IDE exception handler, which he possibly already is used to due to normal IDE errors that may occur, and just clicks it and it gets sent).
What I worried about si that implementing something yourself might have more friction, and getting people to respond to github issues too… did that turn out to be the case for you at least somewhat? Interested to know whether my worry is founded or not
As per JetBrains Marketplace team, there is an internal development activity with fixes, along with more new features to be coming soon.
You can find ready-to-use implementation for the custom exception handler.
I’d say people are happy to send reports and get feedback from the plugin author. GitHub issues are also useful for feature requests.
I have a positive experience with my plugins, like extra-icons (example 1 and 2).
My exception reporter, just in case (mostly based on the work of other plugin developers, thx to them
). It prefills a GitHub issue with some info on the OS, the plugin, the stacktrace, and it suggests to add more details. The stacktarce can be truncated because everything is passed via the url, and some old browser (mostly IE) limit it to 8192 characters:
package lermitage.intellij.commons;
import com.intellij.DynamicBundle;
import com.intellij.ide.BrowserUtil;
import com.intellij.openapi.application.ApplicationInfo;
import com.intellij.openapi.application.ModalityState;
import com.intellij.openapi.diagnostic.ErrorReportSubmitter;
import com.intellij.openapi.diagnostic.IdeaLoggingEvent;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.diagnostic.SubmittedReportInfo;
import com.intellij.openapi.util.NlsActions;
import com.intellij.util.Consumer;
import com.intellij.util.ModalityUiUtil;
import org.apache.commons.lang3.SystemUtils;
import org.apache.http.client.utils.URIBuilder;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.awt.*;
import java.net.URI;
import java.net.URISyntaxException;
import java.text.MessageFormat;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@SuppressWarnings("HardCodedStringLiteral")
public class MyErrorReportSubmitter extends ErrorReportSubmitter {
private static final @NonNls Logger LOGGER = MyLogger.getLogger();
private static final int MAX_GITHUB_URI_LENGTH = 8192;
@Override
public @NlsActions.ActionText @NotNull String getReportActionText() {
if (DynamicBundle.getLocale().getCountry().equalsIgnoreCase("CN") &&
DynamicBundle.getLocale().getLanguage().equalsIgnoreCase("zh")) {
return MessageFormat.format("在GitHub上向{0}报告", ManagedGlobals.DISPLAY_NAME);
}
return MessageFormat.format("Report to {0} on GitHub", ManagedGlobals.DISPLAY_NAME);
}
@Override
public boolean submit(IdeaLoggingEvent @NotNull [] events,
@Nullable String additionalInfo,
@NotNull Component parentComponent,
@NotNull Consumer<? super SubmittedReportInfo> consumer) {
try {
URI uri = constructNewGitHubIssueUri(events, additionalInfo);
ModalityUiUtil.invokeLaterIfNeeded(ModalityState.nonModal(), () -> BrowserUtil.browse(uri));
} catch (Exception e) {
LOGGER.error("Failed to prepare error reporter", e);
return false;
}
return true;
}
URI constructNewGitHubIssueUri(IdeaLoggingEvent[] events, @Nullable String additionalInfo) throws URISyntaxException {
URIBuilder uriBuilder;
uriBuilder = new URIBuilder(ManagedGlobals.NEW_ISSUE_REPORT_URL);
String title = Stream.of(events)
.map(event -> {
Throwable throwable = event.getThrowable();
String exceptionMessage = throwable == null ? event.getMessage() : event.getThrowableText().lines().findFirst().orElse("");
return exceptionMessage == null ? "" : exceptionMessage.stripTrailing();
})
.collect(Collectors.joining("; "));
uriBuilder.setParameter("title", title);
uriBuilder.setParameter("labels", "bug");
URI uri;
List<String> reportBodyLines = getReportBody(events, additionalInfo).lines().collect(Collectors.toList());
do {
// Let's cut the body gradually line-by-line until the resulting URI fits into the GitHub limits.
// It's hard to predict the perfect exact cut in advance due to URL encoding.
reportBodyLines = reportBodyLines.subList(0, reportBodyLines.size() - 1);
uriBuilder.setParameter("body", reportBodyLines.stream().collect(Collectors.joining(System.lineSeparator())));
uri = uriBuilder.build();
} while (uri.toString().length() > MAX_GITHUB_URI_LENGTH);
return uri;
}
private String getReportBody(
IdeaLoggingEvent[] events,
@Nullable String additionalInfo) {
String reportBody = getBugTemplate();
for (java.util.Map.Entry<String, String> entry : getTemplateVariables(events, additionalInfo).entrySet()) {
reportBody = reportBody.replace("%" + entry.getKey() + "%", entry.getValue());
}
return reportBody;
}
private Map<String, String> getTemplateVariables(
IdeaLoggingEvent[] events,
@Nullable String additionalInfo) {
Map<String, String> templateVariables = new HashMap<>();
templateVariables.put("ide", ApplicationInfo.getInstance().getFullApplicationName());
String pluginVersion = MyCommonUtils.getPluginVersion();
templateVariables.put("myPluginVersion", ManagedGlobals.DISPLAY_NAME + " (" + ManagedGlobals.PLUGIN_ID + ") " + pluginVersion);
String osName = SystemUtils.OS_NAME;
String osVersion = SystemUtils.OS_VERSION;
templateVariables.put("os", osName + " " + osVersion);
templateVariables.put("additionalInfo", additionalInfo == null ? "N/A" : additionalInfo);
String nl = System.lineSeparator();
String stacktraces = Stream.of(events)
.map(event -> {
// This message is distinct from the throwable's message:
// in `LOG.error(message, throwable)`, it's the first parameter.
String messagePart = event.getMessage() != null ? (event.getMessage() + nl + nl) : "";
String throwablePart = shortenExceptionsStack(event.getThrowableText().stripTrailing());
return nl + messagePart + throwablePart + nl;
})
.collect(Collectors.joining(nl + nl));
templateVariables.put("stacktraces", stacktraces);
return templateVariables;
}
private String shortenExceptionsStack(String stackTrace) {
String nl = System.lineSeparator();
int rootCauseIndex = Math.max(
stackTrace.lastIndexOf("Caused by:"),
stackTrace.lastIndexOf("\tSuppressed:"));
if (rootCauseIndex != -1) {
String rootCauseStackTrace = stackTrace.substring(rootCauseIndex);
String[] lines = stackTrace.substring(0, rootCauseIndex).split(nl);
StringBuilder resultString = new StringBuilder();
for (int i = 0; i < lines.length; i++) {
if (lines[i].contains("Caused by:") || lines[i].contains("Suppressed:") || i == 0) {
resultString.append(lines[i]).append(nl);
if (i + 1 < lines.length) {
resultString.append(lines[i + 1]).append("...").append(nl);
}
}
}
return resultString.append(rootCauseStackTrace).toString();
}
return stackTrace;
}
private String getBugTemplate() {
return """
## Running environment
- %myPluginVersion%
- %ide%
- %os%
## Bug description
Please include steps to reproduce (like `go to...`/`click on...` etc.) + expected and actual behaviour.
## Additional info
%additionalInfo%
## Stack trace
```%stacktraces%
""";
}
}
<extensions defaultExtensionNs="com.intellij">
<errorHandler implementation="lermitage.intellij.commons.MyErrorReportSubmitter"/>
I share this code across all my paid plugins, this is why it’s a bit suboptimal.
My opinion on the JetBrainsMarketplaceErrorReportSubmitter is that it will be a great feature in the future. For now it’s too limited and its development is too slow, and I can’t wait.

