You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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"场景出现:

  1. 在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
  }
}
  1. 添加else块,禁止非"on-failure"场景出现该属性:
"if": {
  "properties": {
    "restart": { "const": "on-failure" }
  }
},
"then": {}, // 这里可以留空,因为属性已在properties定义
"else": {
  "not": {
    "required": ["restartAttempts"]
  }
},
"required": ["command"],
"additionalProperties": false

内容的提问来源于stack exchange,提问作者Fayeure

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 19:40:54