[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.<anonymous> (/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.<anonymous> (/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 
```
This commit is contained in:
Kristjan ESPERANTO
2025-10-23 22:48:16 +02:00
committed by GitHub
parent c9eecddf23
commit 9ad5618843
2 changed files with 28 additions and 13 deletions

View File

@@ -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

View File

@@ -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);
}