From 9ad56188430c26d21b1aab05707ba7c9af60c45e Mon Sep 17 00:00:00 2001 From: Kristjan ESPERANTO <35647502+KristjanESPERANTO@users.noreply.github.com> Date: Thu, 23 Oct 2025 22:48:16 +0200 Subject: [PATCH] [check_config] refactor: improve error handling (#3927) - Combine file existence and permission checks with better error messages - Replace thrown exceptions with clean error output (no stack traces) - Support custom module positions by changing strict validation to warnings - Add missing process.exit(1) after validation errors Users now see clear, actionable error messages without stack traces, and custom region configurations work correctly. ## example before ```bash $ npm run start > magicmirror@2.34.0-develop start > node --run start:x11 [2025-10-22 17:56:06.303] [LOG] Starting MagicMirror: v2.34.0-develop [2025-10-22 17:56:06.304] [LOG] Loading config ... [2025-10-22 17:56:06.304] [LOG] config template file not exists, no envsubst [2025-10-22 17:56:06.356] [ERROR] File not found: /home/kristjan/MagicMirror/config/config.js No config file present! [2025-10-22 17:56:06.356] [ERROR] [checkconfig] Error: Error: ENOENT: no such file or directory, access '/home/kristjan/MagicMirror/config/config.js' No permission to access config file! at checkConfigFile (/home/kristjan/MagicMirror/js/check_config.js:43:9) at Object. (/home/kristjan/MagicMirror/js/check_config.js:138:2) at Module._compile (node:internal/modules/cjs/loader:1714:14) at Module._extensions..js (node:internal/modules/cjs/loader:1848:10) at Module.load (node:internal/modules/cjs/loader:1448:32) at Module._load (node:internal/modules/cjs/loader:1270:12) at c._load (node:electron/js2c/node_init:2:17993) at TracingChannel.traceSync (node:diagnostics_channel:322:14) at wrapModuleLoad (node:internal/modules/cjs/loader:244:24) at Module.require (node:internal/modules/cjs/loader:1470:12) at require (node:internal/modules/helpers:147:16) at loadConfig (/home/kristjan/MagicMirror/js/app.js:126:3) at App.start (/home/kristjan/MagicMirror/js/app.js:291:18) at Object. (/home/kristjan/MagicMirror/js/electron.js:228:7) at Module._compile (node:internal/modules/cjs/loader:1714:14) at Module._extensions..js (node:internal/modules/cjs/loader:1848:10) ``` ## example after ```bash $ npm run start > magicmirror@2.34.0-develop start > node --run start:x11 [2025-10-22 21:33:27.930] [LOG] Starting MagicMirror: v2.34.0-develop [2025-10-22 21:33:27.931] [LOG] Loading config ... [2025-10-22 21:33:27.931] [LOG] config template file not exists, no envsubst [2025-10-22 21:33:27.985] [ERROR] [check_config] File not found: /home/kristjan/MagicMirror/config/config.js ``` --- CHANGELOG.md | 1 + js/check_config.js | 40 +++++++++++++++++++++++++++------------- 2 files changed, 28 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b62d155d..d52394e7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,7 @@ planned for 2026-01-01 ### Changed - [core] refactor: replace `module-alias` dependency with internal alias resolver (#3893) +- [check_config] refactor: improve error handling (#3927) - [calendar] test: remove "Recurring event per timezone" test (#3929) ### Fixed diff --git a/js/check_config.js b/js/check_config.js index 033b3198..e1108ed1 100644 --- a/js/check_config.js +++ b/js/check_config.js @@ -31,16 +31,18 @@ function getConfigFile () { function checkConfigFile () { const configFileName = getConfigFile(); - // Check if file is present - if (fs.existsSync(configFileName) === false) { - throw new Error(`File not found: ${configFileName}\nNo config file present!`); - } - - // Check permission + // Check if file exists and is accessible try { - fs.accessSync(configFileName, fs.constants.F_OK); + fs.accessSync(configFileName, fs.constants.R_OK); } catch (error) { - throw new Error(`${error}\nNo permission to access config file!`); + if (error.code === "ENOENT") { + Log.error(`File not found: ${configFileName}`); + } else if (error.code === "EACCES") { + Log.error(`No permission to read config file: ${configFileName}`); + } else { + Log.error(`Cannot access config file: ${configFileName}\n${error.message}`); + } + process.exit(1); } // Validate syntax of the configuration file. @@ -75,7 +77,8 @@ function checkConfigFile () { for (const error of errors) { errorMessage += `\nLine ${error.line} column ${error.column}: ${error.message}`; } - throw new Error(errorMessage); + Log.error(errorMessage); + process.exit(1); } } @@ -102,8 +105,7 @@ function validateModulePositions (configFileName) { type: "string" }, position: { - type: "string", - enum: positionList + type: "string" } }, required: ["module"] @@ -119,6 +121,16 @@ function validateModulePositions (configFileName) { const valid = validate(data); if (valid) { Log.info(styleText("green", "Your modules structure configuration doesn't contain errors :)")); + + // Check for unknown positions (warning only, not an error) + if (data.modules) { + for (const [index, module] of data.modules.entries()) { + if (module.position && !positionList.includes(module.position)) { + Log.warn(`Module ${index} ("${module.module}") uses unknown position: "${module.position}"`); + Log.warn(`Known positions are: ${positionList.join(", ")}`); + } + } + } } else { const module = validate.errors[0].instancePath.split("/")[2]; const position = validate.errors[0].instancePath.split("/")[3]; @@ -130,13 +142,15 @@ function validateModulePositions (configFileName) { } else { errorMessage += validate.errors[0].message; } - Log.error("[checkconfig]", errorMessage); + Log.error(errorMessage); + process.exit(1); } } try { checkConfigFile(); } catch (error) { - Log.error("[checkconfig]", error); + const message = error && error.message ? error.message : error; + Log.error(`Unexpected error: ${message}`); process.exit(1); }