One script with kind: "Expression" throws in WorkArea.attaching and blanks the entire UI
Environment
|
|
| NetPad |
0.12.0, netpad-0.12.0-linux-amd64.deb (Electron variant) |
| OS |
Ubuntu 26.04 LTS |
| SDKs |
.NET 9.0.119 and .NET 10.0.110 |
Symptom
The app starts, the window renders, and a script tab loads with working syntax highlighting,
CodeLens and inlay hints — but there is no Explorer pane, no Output pane and no Namespaces
pane, and View → Explorer (Alt+E), View → Output (Ctrl+R) and View → Namespaces
(Alt+N) all do nothing when clicked.
Nothing is surfaced to the user: no toast, no error dialog, and the backend log
(~/.local/share/NetPad/Logs/) is completely clean. From the outside it looks like the pane
toggles are simply broken, which sent me chasing GPU/Wayland and stale-state theories for a
while before I opened DevTools.
Root cause
The renderer console shows:
Uncaught (in promise) Error: Unhandled script kind: Expression
at ViewableAppScriptDocument.getLanguageFromScriptKind (…bundle.js:1:233246)
at new ViewableAppScriptDocument (…bundle.js:1:232788)
at WorkArea.createViewableAppScriptDocument (…bundle.js:1:183353)
at …bundle.js:1:180583
at Array.map (<anonymous>)
at WorkArea.attaching (…bundle.js:1:180571)
at Controller.$t
at Controller.bind
at Controller.activate
WorkArea.attaching does an Array.map over the open scripts to build viewable documents.
getLanguageFromScriptKind has no case for Expression, so it throws — and because the throw
escapes the map, WorkArea.attaching aborts and the whole work area never mounts. The pane
toggles then have nothing to toggle.
So a single script with an unhandled kind takes down the entire UI, and one of mine did.
92 scripts, 91 Program, 1 Expression.
Reproduction
The offending script was empty apart from its config line:
c0ab4f47-4ec6-5e9a-8b33-bbef8f65412d
{"config":{"kind":"Expression","targetFrameworkVersion":"DotNet10","optimizationLevel":"Debug","useAspNet":false,"namespaces":["System", …],"references":[]},"dataConnection":null}
#Code
- Place a
.netpad file with "kind":"Expression" in the scripts directory.
- Open it so it lands in
session.openScripts (~/.local/share/NetPad/key-values.txt).
- Restart NetPad — the work area no longer mounts, and it stays broken across restarts
because the script is reopened from the persisted session.
Changing that one file to "kind":"Program" restores the UI completely.
Where the Expression kind came from
The LINQPad import. The original query was:
<Query Kind="Expression" />
LINQPad's Expression kind is imported and persisted by the backend, but the frontend has no
mapping for it — so the two sides disagree about what kinds are valid. Anyone importing a
LINQPad library containing an expression-kind query will hit this, and the failure gives no
indication of which script or which setting is responsible.
Suggested fix
Two independent things, both worth doing:
- Handle
Expression in getLanguageFromScriptKind (map it to C#), or reject the kind at
import time and convert it to Program/Statements so it can never be persisted.
- Make
WorkArea.attaching resilient. Wrap the per-script
createViewableAppScriptDocument call so one bad document is skipped — logged and surfaced
as a notification naming the offending script — instead of aborting the entire work area.
Even once Expression is handled, any future unmapped kind or malformed script would
otherwise reproduce a total UI blackout with no user-visible error.
The second point is the important one: the failure mode is drastically out of proportion to the
cause, and gives the user nothing to go on.
One script with
kind: "Expression"throws inWorkArea.attachingand blanks the entire UIEnvironment
netpad-0.12.0-linux-amd64.deb(Electron variant)Symptom
The app starts, the window renders, and a script tab loads with working syntax highlighting,
CodeLens and inlay hints — but there is no Explorer pane, no Output pane and no Namespaces
pane, and
View → Explorer(Alt+E),View → Output(Ctrl+R) andView → Namespaces(Alt+N) all do nothing when clicked.
Nothing is surfaced to the user: no toast, no error dialog, and the backend log
(
~/.local/share/NetPad/Logs/) is completely clean. From the outside it looks like the panetoggles are simply broken, which sent me chasing GPU/Wayland and stale-state theories for a
while before I opened DevTools.
Root cause
The renderer console shows:
WorkArea.attachingdoes anArray.mapover the open scripts to build viewable documents.getLanguageFromScriptKindhas no case forExpression, so it throws — and because the throwescapes the
map,WorkArea.attachingaborts and the whole work area never mounts. The panetoggles then have nothing to toggle.
So a single script with an unhandled kind takes down the entire UI, and one of mine did.
92 scripts, 91
Program, 1Expression.Reproduction
The offending script was empty apart from its config line:
.netpadfile with"kind":"Expression"in the scripts directory.session.openScripts(~/.local/share/NetPad/key-values.txt).because the script is reopened from the persisted session.
Changing that one file to
"kind":"Program"restores the UI completely.Where the
Expressionkind came fromThe LINQPad import. The original query was:
LINQPad's
Expressionkind is imported and persisted by the backend, but the frontend has nomapping for it — so the two sides disagree about what kinds are valid. Anyone importing a
LINQPad library containing an expression-kind query will hit this, and the failure gives no
indication of which script or which setting is responsible.
Suggested fix
Two independent things, both worth doing:
ExpressioningetLanguageFromScriptKind(map it to C#), or reject the kind atimport time and convert it to
Program/Statementsso it can never be persisted.WorkArea.attachingresilient. Wrap the per-scriptcreateViewableAppScriptDocumentcall so one bad document is skipped — logged and surfacedas a notification naming the offending script — instead of aborting the entire work area.
Even once
Expressionis handled, any future unmapped kind or malformed script wouldotherwise reproduce a total UI blackout with no user-visible error.
The second point is the important one: the failure mode is drastically out of proportion to the
cause, and gives the user nothing to go on.