Skip to content

Troubleshooting

This page covers solutions to common problems. If yours is not listed, feel free to open an issue on GitHub.


Shoji does not start

Check Hammerspoon permissions

Hammerspoon requires Accessibility permissions to manage windows.

  1. Open System Settings (or System Preferences on older macOS)
  2. Navigate to Privacy & Security > Accessibility
  3. Ensure Hammerspoon is listed and enabled
  4. If enabled but not working, remove and re-add it

After changing permissions, reload Hammerspoon config (Cmd+Alt+Ctrl+R) or restart Hammerspoon.

Check for Lua errors

Open the Hammerspoon console (Cmd+Alt+C) and look for errors.

Common errors:

ErrorWhat it means
module 'Shoji' not foundShoji is not in the expected location
attempt to call a nil valueAPI usage error or version mismatch
invalid config keyTypo in configuration option name

Verify Spoon installation

Check the installation path:

-- Check Spoon directory
print(hs.spoons.installDirectory)
-- Expected: ~/.hammerspoon/Spoons/
-- Check if Shoji is found
print(hs.spoons.scriptPath("Shoji"))
-- Should show path to Shoji.spoon

Windows are not tiling

Verify Shoji is running

Paste this into the Hammerspoon console:

print(spoon.Shoji._started) -- Should print: true

If you see false or nil, Shoji has not started. Add spoon.Shoji:start() to your config and reload.

Check window filter settings

Apps in filter_apps may be excluded from tiling:

print("Mode: " .. spoon.Shoji.config.filter_mode)
print("Apps: " .. hs.inspect(spoon.Shoji.config.filter_apps))
  • blocklist mode: listed apps are excluded
  • allowlist mode: only listed apps are tiled

Check minimum size settings

Windows below the minimum size are excluded:

print("Min width: " .. spoon.Shoji.config.min_width)
print("Min height: " .. spoon.Shoji.config.min_height)

Set these to 0 to disable size filtering.

Check if window is floating

Floating windows are excluded:

local win = hs.window.focusedWindow()
if win then
print(spoon.Shoji.state:isFloating(win:id()))
end

Use toggle_float to change the floating state.


Hotkeys do not work

Check for conflicts

Another app or Hammerspoon binding may be using the same hotkey:

for _, hk in ipairs(hs.hotkey.getHotkeys()) do
print(hk.idx, hk.msg)
end

Verify binding succeeded

print(hs.inspect(spoon.Shoji._hotkeys))

If empty, hotkeys were not bound:

spoon.Shoji:bindHotkeys(
spoon.Shoji.actions.DEFAULT_HOTKEYS
)

Test action directly

Bypass the hotkey and call the action directly:

spoon.Shoji.actions.focusLeft()
spoon.Shoji.actions.cycleLayout()

If the action works, the problem is with the hotkey binding, not the action.


Layout issues

Windows overlap or have gaps

Force a retile:

spoon.Shoji:retile()

Or reset layout parameters (ratio and nmaster) to defaults:

spoon.Shoji.actions.retileSpace()

Layout does not change

Check that the layout is in enabled_layouts:

print(hs.inspect(spoon.Shoji.config.enabled_layouts))

Layouts not in this list cannot be activated via cycle_layout. Use the set_layout_<name> actions to switch directly to any registered layout.

BSP layout behaves unexpectedly

Reset BSP state (clears split ratios and rebuilds the tree):

spoon.Shoji.actions.retileSpace()

Performance issues

Slow retiling

Profile a retile:

local start = hs.timer.absoluteTime()
spoon.Shoji:retile()
local elapsed = (hs.timer.absoluteTime() - start) / 1000000
print(elapsed .. "ms")

Typical retile takes under 50ms. If slow:

  • Check hooks for expensive operations
  • Reduce window count on the space
  • Disable drag-swap if not using it

High CPU usage

Drag-swap monitors mouse events continuously. Disable if not needed:

spoon.Shoji:configure({ drag_swap = false })

IPC issues

hs command not found

Install the Hammerspoon CLI (installs to /usr/local/bin/):

hs.ipc.cliInstall()

IPC commands return nil

Verify Shoji is loaded and started:

Terminal window
hs -c 'print(spoon.Shoji._started)'

If nil, check the Hammerspoon config (init.lua):

hs.loadSpoon("Shoji")
spoon.Shoji:configure({ ... })
spoon.Shoji:start()

Debugging

Enable debug logging

spoon.Shoji.logger = hs.logger.new("Shoji", "debug")

Log levels: error, warning, info, debug, verbose

View log output

Open the Hammerspoon console (Cmd+Alt+C). Log messages appear in real time.

Inspect current state

local spaceID = hs.spaces.focusedSpace()
print("macOS Space: " .. spaceID)
print("Layout: " .. spoon.Shoji.state:getSpaceLayout(spaceID))
print("Windows: " .. hs.inspect(spoon.Shoji.state:getWindowOrder(spaceID)))
print("Ratio: " .. spoon.Shoji.state:getMainRatio(spaceID))

Force reload

Reload the Hammerspoon configuration:

hs.reload()

Or click the Hammerspoon menu bar icon and select Reload config.


Hook issues

Hook recursion warning

If you see Hook recursion limit reached:

hooks = {
after_tile = function(spaceID)
spoon.Shoji:retile() -- This creates infinite recursion!
end,
}

Don’t call tiling functions from tiling hooks. The recursion limit (10) exists to prevent infinite loops.

Hook errors silently failing

Hooks are wrapped in pcall so errors don’t crash Shoji. Check the console:

spoon.Shoji.logger = hs.logger.new("Shoji", "debug")

Look for [ERROR] Hook <name> failed: messages.


Multi-monitor issues

Windows tile on wrong screen

Each macOS Space is tied to a specific screen. Shoji tiles per macOS Space, not per screen. If a window appears on the wrong screen, check which macOS Space it belongs to:

local win = hs.window.focusedWindow()
print(hs.inspect(hs.spaces.windowSpaces(win)))

Layout resets when switching screens

Each macOS Space maintains independent layout state. Switching between macOS Spaces on different screens does not reset layouts. The previous state is preserved.


App-specific issues

Dialogs and popups cause retiling

Some apps create transient windows that trigger tiling events. Add them to the blocklist:

spoon.Shoji:configure({
filter_mode = "blocklist",
filter_apps = {
"com.apple.systempreferences", -- System Settings dialogs
"com.apple.finder", -- Finder dialogs
},
})

Electron apps have incorrect sizes

Some Electron apps report incorrect initial sizes. Enable retile_on_focus to correct layouts when you focus these windows:

spoon.Shoji:configure({
retile_on_focus = true,
})

Getting help

If none of this resolves the issue:

  1. Search GitHub Issues for similar problems
  2. Open a new issue with:
    • Hammerspoon version (hs.processInfo.version)
    • macOS version
    • Minimal config that reproduces the problem
    • Console output and errors