JSON Schema条件判断失效:restartAttempts属性无法正常生效
问题:JSON Schema if/then逻辑未生效,restartAttempts属性被误判为不允许
我在编写配置文件的JSON Schema时遇到问题:配置对象包含tasks数组,其中restart是枚举类型,我希望仅当restart设为"on-failure"时,才允许出现"restartAttempts"属性。虽然用了if/then块实现,但即使restart设置为"on-failure",neovim搭配Mason和最新版jsonls(vscode-json-language-server)仍提示“property restartAttempts is not allowed”语法错误。
错误的Schema代码如下:
{ "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "TMConfig", "description": "TaskMaster configuration file", "type": "object", "properties": { "tasks": { "type": "array", "description": "The tasks to be executed", "items": { "type": "object", "properties": { "command": { "type": "string", "description": "The executable to run" }, "arguments": { "type": "array", "default": [], "description": "The arguments to pass to the executable\nDefault is []", "items": { "type": "string" } }, "startAtLaunch": { "type": "boolean", "default": true, "description": "Wether or not to start the process(es) at launch\nDefault is true" }, "instances": { "type": "number", "default": 1, "description": "The number of instances of the process to run\nDefault is 1", "minimum": 1 }, "restart": { "enum": ["always", "never", "on-failure", "unless-stopped"], "default": "on-failure", "description": "'always': always restart the process if it exits\n'never': never restart the process\n'on-failure': restart if the process exits with an error code\n'unless-stopped': restart the process except if the user stops it manually through the console\nDefault is 'on-failure'" }, "expectedExitStatus": { "type": "number", "default": 0, "description": "The expected success exit status code for the process(es)\nDefault is 0" }, "startTime": { "type": "number", "default": 0, "description": "The time to wait (in milliseconds) before considering that a process is sucessfuly started\nDefault is 0", "minimum": 0 }, "stopTime": { "type": "number", "default": 5000, "description": "The time to wait (in milliseconds) after a graceful stop before killing a process\nDefault is 5000", "minimum": 0 }, "stopSignal": { "enum": [ "SIGINT", "SIGQUIT", "SIGTERM", "SIGUSR1", "SIGUSR2", "SIGSTOP", "SIGTSTP" ], "default": "SIGSTOP", "description": "The signal used to quit a process gracefully\nDefault is 'SIGSTOP'" }, "stdout": { "enum": ["ignore", "inherit", "redirect"], "default": "redirect", "description": "'ignore': ignore stdout\n'inherit': show stdout on taskmaster console\n'redirect': redirect stdout to a log file\nDefault is 'redirect'" }, "stderr": { "enum": ["ignore", "inherit", "redirect"], "default": "redirect", "description": "'ignore': ignore stderr\n'inherit': show stderr on taskmaster console\n'redirect': redirect stderr to a log file\nDefault is 'redirect'" }, "logDir": { "type": "string", "default": "/var/log/taskmaster", "description": "The path in which to save output log files\nDefault is /var/log/taskmaster" }, "environment": { "type": "object", "default": {}, "description": "Variables to pass as environment to the process(es)\nDefault is {}", "required": [], "additionalProperties": { "type": "string" } }, "workingDirectory": { "type": "string", "default": ".", "description": "The working directory\nDefault is '.'" }, "permissions": { "type": ["number", "null"], "default": null, "description": "The permissions umask to set before launching the program, or null to leave the permissions as they are\nDefault is null", "maximum": 777 } }, "if": { "properties": { "restart": { "const": "on-failure" } } }, "then": { "properties": { "restartAttempts": { "type": "number", "default": 5, "description": "The number of restart attempts (or 0 for infinite attemps) if 'restart' is set to 'on-failure'\nDefault is 5", "minimum": 0 } } }, "required": ["command"], "additionalProperties": false }, "additionalItems": false } } }
原因与解决方案
核心问题
你设置了additionalProperties: false,这个关键字会直接拒绝所有未在根级properties中定义的属性。尽管then块里添加了restartAttempts,但additionalProperties: false的优先级更高,会拦截这个新增属性。
方案1:使用unevaluatedProperties: false(推荐,JSON Schema 2019-09+)
将根级的additionalProperties: false替换为unevaluatedProperties: false,这个关键字会忽略通过if/then等逻辑新增的属性,只拒绝未被任何schema规则覆盖的属性。
修正后的关键部分:
"then": { "properties": { "restartAttempts": { "type": "number", "default": 5, "description": "The number of restart attempts (or 0 for infinite attemps) if 'restart' is set to 'on-failure'\nDefault is 5", "minimum": 0 } } }, "required": ["command"], "unevaluatedProperties": false
方案2:兼容旧版本Schema
如果需要兼容不支持unevaluatedProperties的旧版本,可以先把restartAttempts放到根级properties中,再用else块禁止它在非"on-failure"场景出现:
- 在
properties里添加restartAttempts的定义:
"properties": { // ... 其他属性 ... "restartAttempts": { "type": "number", "default": 5, "description": "The number of restart attempts (or 0 for infinite attemps) if 'restart' is set to 'on-failure'\nDefault is 5", "minimum": 0 } }
- 添加else块,禁止非"on-failure"场景出现该属性:
"if": { "properties": { "restart": { "const": "on-failure" } } }, "then": {}, // 这里可以留空,因为属性已在properties定义 "else": { "not": { "required": ["restartAttempts"] } }, "required": ["command"], "additionalProperties": false
内容的提问来源于stack exchange,提问作者Fayeure
相关产品推荐
相关产品推荐

