lsp.client: Breakpoints window throws ClassCastException on every repaint while a DAP session is stopped (BreakpointModel passes a Line where DAPStackTraceAnnotationHolder.contains casts to Annotatable[])

Open Beginner friendly
#9,621 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Assessment

Difficulty
2/5
Estimated time
1-3 hours
Newbie friendliness
88/100
Issue type
Bug
Clarity
Clearly specified
Activity status
Active
Tech stack
java
Domain
devtools

Research direction

Read org.netbeans.modules.lsp.client.debugger.breakpoints.BreakpointModel.getIconBase and DAPStackTraceAnnotationHolder.contains first, focusing on the argument types and the reported cast. Reproduce with a stopped DAP session and the Breakpoints window open; done means the breakpoint row shows the hit or normal icon as appropriate and no ClassCastException is logged during repaint.

Written by the indexing model from the issue text.

Description

LSP
Apache NetBeans version

Apache NetBeans 31

What happened

With the Breakpoints window open while a DAP debug session (ide/lsp.client's DAPDebugger) is stopped at a breakpoint, every repaint of the window logs a SEVERE ClassCastException and the status bar's error badge lights. The breakpoint rows still list, but the "breakpoint hit" icon is never painted.

The cause is a type disagreement between two classes in org.netbeans.modules.lsp.client.debugger (present on master, commit 4a516704, and on the release310 tag):

  • breakpoints/BreakpointModel.getIconBase(Object) calls
    DAPStackTraceAnnotationHolder.contains(debugger.getCurrentLine(), breakpoint.getLine())DAPDebugger.getCurrentLine() returns a org.openide.text.Line.
  • DAPStackTraceAnnotationHolder.contains(Object currentLine, Line line) begins with
    final Annotatable[] a = (Annotatable[]) currentLine; (line 102) — it expects the holder's annotation array, not a Line.

So whenever getCurrentLine() is non-null (any stopped DAP session) and the model paints a DAPLineBreakpoint row, the renderer throws. Expected: the row paints LINE_BREAKPOINT_PC when the current line is the breakpoint's line, and LINE_BREAKPOINT otherwise, with nothing logged.

A one-line fix either way: contains could accept a Line (compare currentLine.equals(line), plus the Line.Part case), or getIconBase could pass the holder's annotations instead of the debugger's current line.

SEVERE [global]
java.lang.ClassCastException: class org.openide.text.EditorSupportLineSet$SupportLine cannot be cast to class [Lorg.openide.text.Annotatable; (org.openide.text.EditorSupportLineSet$SupportLine and [Lorg.openide.text.Annotatable; are in unnamed module of loader org.netbeans.StandardModule$OneModuleClassLoader @66edbc51)
    at org.netbeans.modules.lsp.client.debugger.DAPStackTraceAnnotationHolder.contains(DAPStackTraceAnnotationHolder.java:102)
    at org.netbeans.modules.lsp.client.debugger.breakpoints.BreakpointModel.getIconBase(BreakpointModel.java:90)
    at org.netbeans.spi.viewmodel.Models$DelegatingNodeModel.getIconBaseWithExtension(Models.java:3622)
    at org.netbeans.spi.viewmodel.Models$CompoundModel.getIconBaseWithExtension(Models.java:4778)
    at org.netbeans.modules.viewmodel.TreeModelNode.setModelIcon(TreeModelNode.java:889)
    at org.netbeans.modules.viewmodel.TreeModelNode.getIcon(TreeModelNode.java:901)
    at org.openide.explorer.view.NodeRenderDataProvider.getIcon(NodeRenderDataProvider.java:104)
    at org.netbeans.swing.outline.DefaultOutlineCellRenderer.getTableCellRendererComponent(DefaultOutlineCellRenderer.java:314)
    at org.openide.explorer.view.OutlineView$OutlineViewOutline$TranslatedTableCellRenderer.getTableCellRendererComponent(OutlineView.java:2297)
    at org.netbeans.modules.viewmodel.DelegatingCellRenderer.getTableCellRendererComponent(DelegatingCellRenderer.java:66)
    at org.openide.explorer.view.OutlineView$OutlineViewOutline$TranslatedTableCellRenderer.getTableCellRendererComponent(OutlineView.java:2297)
    at java.desktop/javax.swing.JTable.prepareRenderer(JTable.java:5818)
    at java.desktop/javax.swing.plaf.basic.BasicTableUI.paintCell(BasicTableUI.java:2187)
    at java.desktop/javax.swing.plaf.basic.BasicTableUI.paintCells(BasicTableUI.java:2086)
Language / Project Type / NetBeans Component

NetBeans Platform application using the ide/lsp.client DAP debugger (org.netbeans.modules.lsp.client.debugger), JavaScript debugged through a DAP adapter (js-debug)

How to reproduce
  1. Any DAP-backed debugger using org.netbeans.modules.lsp.client.debugger.api.DAPConfiguration (we use js-debug for Node; the adapter does not matter — the throw happens in the Breakpoints view's model).
  2. Set one line breakpoint via DAPLineBreakpoint (gutter click / ⌘F8 on a JavaScript file).
  3. Open Window ▸ Debugging ▸ Breakpoints.
  4. Launch the debug session and let it stop at the breakpoint.
  5. Observe messages.log: the ClassCastException above, repeated on every repaint of the Breakpoints window (8 times in a two-minute session); the status bar error badge lights; the row keeps the plain breakpoint icon rather than the "hit" icon.

Reading the two source files is enough to see it without running anything: BreakpointModel.getIconBase (lines 84–96 on master) passes debugger.getCurrentLine(), a Line, into DAPStackTraceAnnotationHolder.contains (line 100–102 on master), which casts its first argument to Annotatable[].

Did this work correctly in an earlier version?

No / Don't know

Operating System

macOS 27.0 (build 26A428), arm64

JDK

OpenJDK Runtime Environment Temurin-21.0.4+7 (build 21.0.4+7-LTS), Eclipse Adoptium, arm64

Apache NetBeans packaging

Apache NetBeans platform

Anything else

Every time, for any stopped DAP session, as long as the Breakpoints window is open. Found while working on NMOX Studio (a NetBeans Platform IDE built on RELEASE310); the analysis was made against the shipped bytecode first and then confirmed against the source on master.

Assisted-by: Claude Fable 5.1 (claude-fable-5-1) — investigation and report drafting; filed and reviewed by the reporter.

Are you willing to submit a pull request?

No

Dominant language
Java
Stars
3.1k
Forks
933
Avg merge
4d 12h
Merged PRs (30d)
22

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from apache/netbeans

All issues in apache/netbeans

Similar issues

More Java issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.