Skip to content

[Bug]: Stat Sheet with Handlebars Partials not working at Windows PC due to Invalid Location Exception with /\sheets\myPartial.hbs #5977

Description

@audiooffler

Describe the Bug

Stat sheets based on Handlebars can use partials. This is working fine on MacOS, where file system path delimiters are always /.

But on Windows PC (where file system path delimiters are usually \), the stat sheet is not showing up. The debug log console shows exception. There is a /\ at the beginning of the partials path that is tried to be opened, see com.github.jknack.handlebars.HandlebarsException.

Debug Log Console in MapTool 1.18.6:

10:10:43.709 ERROR com.google.common.eventbus.EventBus.default - Exception thrown by subscriber method onHoverEnter(net.rptools.maptool.client.events.TokenHoverEnter) on subscriber net.rptools.maptool.client.ui.sheet.stats.StatSheetListener@45ea8310 when dispatching event: TokenHoverEnter[token=Token: 72AC49A72FC947A7B22B4269655F8780, zone=Pretitle: Title (tf.scn.user3), shiftDown=false, controlDown=false]
com.github.jknack.handlebars.HandlebarsException: inline@8f41d17:37:12: The partial '/\add-on.tf\sheets\myPartial.hbs' at 'Fehler beim Laden der HTML-Datei von URL lib://\add-on.tf\sheets\myPartial.hbs.' could not be found
    at com.github.jknack.handlebars.internal.Partial.merge(Partial.java:220) ~[handlebars-4.4.0.jar:?]

[...]

Nighly Build (2026-06-17):

08:32:55.599 ERROR com.google.common.eventbus.EventBus.default - Exception thrown by subscriber method onHoverEnter(net.rptools.maptool.client.events.TokenHoverEnter) on subscriber net.rptools.maptool.client.ui.sheet.stats.StatSheetListener@2c798ce6 when dispatching event: TokenHoverEnter[token=Token: D8624A6E6C7E4D5DA8A3D6524D443379, zone=Grasslands, shiftDown=false, controlDown=false]
com.github.jknack.handlebars.HandlebarsException: inline@5673e23e:5:4: The partial '/\sheets\myPartial.hbs' at 'Invalid Location' could not be found
	at com.github.jknack.handlebars.internal.Partial.merge(Partial.java:220)
	at com.github.jknack.handlebars.internal.BaseTemplate.apply(BaseTemplate.java:98)
	at com.github.jknack.handlebars.internal.TemplateList.merge(TemplateList.java:81)
	at com.github.jknack.handlebars.internal.BaseTemplate.apply(BaseTemplate.java:98)
	at com.github.jknack.handlebars.internal.BaseTemplate.apply(BaseTemplate.java:87)
	at com.github.jknack.handlebars.internal.ForwardingTemplate.apply(ForwardingTemplate.java:86)
	at net.rptools.maptool.util.HandlebarsUtil.apply(HandlebarsUtil.java:211)
	at net.rptools.maptool.client.ui.sheet.stats.StatSheet.setContent(StatSheet.java:48)
	at net.rptools.maptool.client.ui.sheet.stats.StatSheetListener.onHoverEnter(StatSheetListener.java:62)
	at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(Unknown Source)
	at java.base/java.lang.reflect.Method.invoke(Unknown Source)
	at com.google.common.eventbus.Subscriber.invokeSubscriberMethod(Subscriber.java:84)
	at com.google.common.eventbus.Subscriber$SynchronizedSubscriber.invokeSubscriberMethod(Subscriber.java:141)
	at com.google.common.eventbus.Subscriber.lambda$dispatchEvent$0(Subscriber.java:70)
	at com.google.common.util.concurrent.DirectExecutor.execute(DirectExecutor.java:30)
	at com.google.common.eventbus.Subscriber.dispatchEvent(Subscriber.java:67)
	at com.google.common.eventbus.Dispatcher$PerThreadQueuedDispatcher.dispatch(Dispatcher.java:112)
	at com.google.common.eventbus.EventBus.post(EventBus.java:262)
	at net.rptools.maptool.client.tool.PointerTool.mouseMoved(PointerTool.java:664)
	at java.desktop/java.awt.AWTEventMulticaster.mouseMoved(Unknown Source)
	at java.desktop/java.awt.Component.processMouseMotionEvent(Unknown Source)
	at java.desktop/javax.swing.JComponent.processMouseMotionEvent(Unknown Source)
	at java.desktop/java.awt.Component.processEvent(Unknown Source)
	at java.desktop/java.awt.Container.processEvent(Unknown Source)
	at java.desktop/java.awt.Component.dispatchEventImpl(Unknown Source)
	at java.desktop/java.awt.Container.dispatchEventImpl(Unknown Source)
	at java.desktop/java.awt.Component.dispatchEvent(Unknown Source)
	at java.desktop/java.awt.LightweightDispatcher.retargetMouseEvent(Unknown Source)
	at java.desktop/java.awt.LightweightDispatcher.processMouseEvent(Unknown Source)
	at java.desktop/java.awt.LightweightDispatcher.dispatchEvent(Unknown Source)
	at java.desktop/java.awt.Container.dispatchEventImpl(Unknown Source)
	at java.desktop/java.awt.Window.dispatchEventImpl(Unknown Source)
	at java.desktop/java.awt.Component.dispatchEvent(Unknown Source)
	at java.desktop/java.awt.EventQueue.dispatchEventImpl(Unknown Source)
	at java.desktop/java.awt.EventQueue$4.run(Unknown Source)
	at java.desktop/java.awt.EventQueue$4.run(Unknown Source)
	at java.base/java.security.AccessController.doPrivileged(Unknown Source)
	at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(Unknown Source)
	at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(Unknown Source)
	at java.desktop/java.awt.EventQueue$5.run(Unknown Source)
	at java.desktop/java.awt.EventQueue$5.run(Unknown Source)
	at java.base/java.security.AccessController.doPrivileged(Unknown Source)
	at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(Unknown Source)
	at java.desktop/java.awt.EventQueue.dispatchEvent(Unknown Source)
	at net.rptools.maptool.client.swing.MapToolEventQueue.dispatchEvent(MapToolEventQueue.java:63)
	at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
	at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
	at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
	at java.desktop/java.awt.EventDispatchThread.pumpEvents(Unknown Source)
	at java.desktop/java.awt.EventDispatchThread.pumpEvents(Unknown Source)
	at java.desktop/java.awt.EventDispatchThread.run(Unknown Source)

To Reproduce

create a new add-on with following content and pack it into a .zip, rename it to .mtlib (you may simply download test.mtlib.zip and rename it to .mtlib).

Load this add-on in MapTool and try to show this stat sheet for a property type Basic token.

library.json
stat_sheets.json
library/
    public/
        sheets/
            mySheet.hbs
            myPartial.hbs

library.json:

 {
   "name": "test",
   "authors": ["audiooffler"],
   "namespace": "io.github.test",
   "shortDescription": "Test add-on with stat sheet using partials",
   "allowsUriAccess": true
 }

stat_sheets.json

{
  "statSheets": [
    {
        "name": "mySheetExample",
        "description": "Example using partials",
        "propertyTypes": ["Basic"],
        "entry": "sheets/mySheet.hbs"
    }
  ]
}

library/public/sheets/mySheet.hbs:

<link rel="stylesheet" href="lib://net.rptools.maptool/css/mt-stat-sheet.css" />
<div id="statSheet" class="statSheet {{statSheetLocation}}">
    <p>Token "{{name}}" (Type: {{tokenType}})</p>
    {{> myPartial}}
</div>

library/public/sheets/myPartial.hbs:

<p>Partial is working.</p>

Expected Behaviour

After loading the add-on with the stat sheet, and creating a token of propertytype Basic (check it's stat sheet is set to Example using partials in token editor), hovering with mouse should show the stat sheet with the following content, as it does sucessfully on MacOS:

Token "Dragon 1" (Type: PC)
Partial is working.

Image

Screenshots

No response

MapTool Info

MapTool 1.18.6 (Windows exe); MapTool Nightly 20260617 (Windows exe)

Desktop

Windows

Additional Context

No response

Metadata

Metadata

Assignees

Labels

Type

No fields configured for Bug.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions