[Virtualizor WHMCS Module] Bug Report: OS Reinstall fails with "The OS submitted is invalid"
Summary
When a client attempts to reinstall the OS on their VPS via the WHMCS Client Area, the operation fails with the error "The OS submitted is invalid", even though the selected OS template is listed as available.
Environment
- Product: Virtualizor WHMCS Module
- Module version: 2.9.6, 2.9.8 (present in all recent versions)
- Affected file: ui/js2/virtualizor.js
- Affected function: os_badges()
- Error key: os_invalid_os in enduser_lang.php
Root Cause
- The os_badges() function only binds a click event on .create_os badge elements.
- When the user opens the dropdown and selects an OS version, a change event fires, but there is NO change event handler to update the hidden field (newos / ps_osid / ei_osid ).
- The hidden field remains at its default value "0", and Virtualizor returns os_invalid_os.
The buggy code
Code
function os_badges(ele1, ele2, prefix) {
prefix = prefix || '';
// Only listens to click - NO change handler
$('.'+prefix+'create_os').click(function(){
var os_id = $(this).find('.version').val();
if(os_id > 1) {
$('#'+ele2).val(os_id);
}
});
// Missing: change handler for the version dropdown
};
Scope
This bug affects all callers of os_badges():
- show_osreinstall_window() line 3847: os_badges('os_list', 'newos') - OS reinstall
- fill_ostemplates() line 10322: os_badges(prefix+'osid-box', prefix+'osid', prefix) - Create / Edit VPS
Patch
File: ui/js2/virtualizor.js
Before:
Code
function os_badges(ele1, ele2, prefix) {
prefix = prefix || '';
$('.'+prefix+'create_os').click(function(){
$(this).siblings().each(function(){
$(this).find('.version').val(-1);
});
$('#'+prefix+'selected_os_icon').remove();
$('#'+ele1+' .'+prefix+'create_os').removeClass('selected');
var os_id = $(this).find('.version').val();
if(os_id > 1) {
$(this).addClass('selected');
$('#'+ele2).val(os_id);
$('.selected').append('... SVG icon ...');
}
});
};
After:
Code
function os_badges(ele1, ele2, prefix) {
prefix = prefix || '';
var select_os = function($badge){
$badge.siblings().each(function(){
$(this).find('.version').val(-1);
});
$('#'+prefix+'selected_os_icon').remove();
$('#'+ele1+' .'+prefix+'create_os').removeClass('selected');
var os_id = $badge.find('.version').val();
if(os_id > 1) {
$badge.addClass('selected');
$('#'+ele2).val(os_id);
$badge.append('... SVG icon ...');
}
};
$('.'+prefix+'create_os').click(function(){
select_os($(this));
});
// FIX: also handle dropdown change event
$('.'+prefix+'create_os .version').change(function(){
select_os($(this).closest('.'+prefix+'create_os'));
});
};
What changed
- Extracted the selection logic into select_os($badge) to avoid code duplication
- Replaced $('.selected').append() with $badge.append() for better precision
- Added a change event handler on the .version dropdown, so the hidden field is updated when the user selects a version
Git Patch
Code
diff --git a/ui/js2/virtualizor.js b/ui/js2/virtualizor.js
--- a/ui/js2/virtualizor.js
+++ b/ui/js2/virtualizor.js
@@ -12021,11 +12021,9 @@ function os_badges(ele1, ele2, prefix) {
prefix = prefix || '';
- // While clicking on the OS Icons we will reset the other dropdowns
- $('.'+prefix+'create_os').click(function(){
-
+ var select_os = function($badge){
// Check for the other OS
- $(this).siblings().each(function(){
+ $badge.siblings().each(function(){
// Reset it to -1
$(this).find('.version').val(-1);
});
@@ -12034,13 +12032,23 @@ function os_badges(ele1, ele2, prefix) {
// Remove the selected class from other divs
$('#'+ele1+' .'+prefix+'create_os').removeClass('selected');
// Get the value which is OSname
- var os_id = $(this).find('.version').val();
+ var os_id = $badge.find('.version').val();
if(os_id > 1) {
- $(this).addClass('selected');
+ $badge.addClass('selected');
$('#'+ele2).val(os_id);
- $('.selected').append('...');
+ $badge.append('...');
}
+ };
+
+ // While clicking on the OS Icons we will reset the other dropdowns
+ $('.'+prefix+'create_os').click(function(){
+ select_os($(this));
+ });
+
+ // FIX: also handle dropdown change event to update hidden field
+ $('.'+prefix+'create_os .version').change(function(){
+ select_os($(this).closest('.'+prefix+'create_os'));
});
};
Recommendation
The guard condition if(os_id > 1) works for numeric OS IDs greater than 1, but would reject string-based OS identifiers (e.g. "ubuntu-2404") or OS ID 1. A more robust guard:
Code
if(os_id !== null && os_id !== undefined && os_id != '-1' && os_id !== '') {
Report prepared: 2026-07-14
|