lyswhut/lx-music-desktop · error · Error
Unknown action: ${action}
Error message
Unknown action: ${action} What it means
Player deep-link action dispatcher in usePlayerAction.ts:32. The switch handles play/pause/skipNext/skipPrev/togglePlay/collect/uncollect/dislike; the default branch throws 'Unknown action: <action>'. The `(action as any ?? '')` cast signals the input is loosely typed at this boundary, so a nullish action becomes 'Unknown action: ' with an empty tail.
Source
Thrown at src/renderer/core/useApp/useDeeplink/usePlayerAction.ts:32
case 'skipNext':
playNext()
break
case 'skipPrev':
playPrev()
break
case 'togglePlay':
togglePlay()
break
case 'collect':
collectMusic()
break
case 'uncollect':
uncollectMusic()
break
case 'dislike':
dislikeMusic()
break
default: throw new Error('Unknown action: ' + (action as any ?? ''))
}
}
}
View on GitHub (pinned to 9c364b482e)
Solutions
- Confirm the action token matches one of the eight supported verbs.
- Tighten the parameter type from `any` to a string-literal union so invalid values are caught at compile time instead of leaking to the switch.
- Wrap the dispatcher in try-catch at the deeplink router and route failures to useDialog().
- Default missing/null action to a no-op or an explicit error before the switch.
Example fix
// before
default: throw new Error('Unknown action: ' + (action as any ?? ''))
// after - typed action, clear message
type PlayerAction = 'play' | 'pause' | 'skipNext' | 'skipPrev' | 'togglePlay' | 'collect' | 'uncollect' | 'dislike'
// in the handler signature: (action: PlayerAction, ...)
default: throw new Error(`Unknown player action: '${String(action ?? '')}'`) Defensive patterns
Strategy: type-guard
Validate before calling
const PLAYER_ACTIONS = new Set(['play','pause','skipNext','skipPrev','togglePlay','collect','uncollect','dislike'])
if (!PLAYER_ACTIONS.has(action)) {
showErrorDialog(`Unknown player action: ${action ?? ''}`)
return
} Type guard
type PlayerAction = 'play' | 'pause' | 'skipNext' | 'skipPrev' | 'togglePlay' | 'collect' | 'uncollect' | 'dislike' const isPlayerAction = (a: unknown): a is PlayerAction => typeof a === 'string' && ['play','pause','skipNext','skipPrev','togglePlay','collect','uncollect','dislike'].includes(a)
Try / catch
try {
playerDispatcher(action, info)
} catch (e) {
errorDialog(e.message)
} Prevention
- Type the action parameter as a string-literal union, not `any`, so invalid values fail at compile time.
- Guard against nullish action before the switch to avoid the empty-suffix 'Unknown action: ' variant.
- Keep the action set in one shared constant referenced by router and dispatcher.
When it happens
Trigger: A player deep link whose action is not in the supported set, or whose action field is null/undefined (yielding the empty-suffix variant), reaches the switch default at usePlayerAction.ts:32.
Common situations: A newer sender emits an action this build doesn't recognize; the URL template omits the action segment so it arrives undefined; an integration typo like 'playNext' instead of 'skipNext'.
Related errors
- Unknown action: ${action}
- Unknown action: ${action}
- Unknown source: ${musicInfo.source}
- id or url missing
- Source no match
AI-assisted analysis of lyswhut/lx-music-desktop@9c364b482e (2026-08-12).
Data as JSON: /api/errors/89ca3c9d3ac29754.
Report an issue: GitHub.