swagger-cli校验报Token "Multiclassing"不存在问题求解
问题描述
使用swagger-cli执行Swagger文档校验命令:
swagger-cli validate src/swagger/swagger.yml
执行后返回报错:
Token "Multiclassing" does not exist.
反复核对所有Multiclassing相关的引用路径,确认路径配置完全正确,且该问题是在更新与Multiclassing完全无关的文档内容后突然出现的。调试后发现:/src/swagger/schemas/common.yml(调试记录中笔误写为comman.yml)末尾choice-model的from字段如果引用OptionSet或Option就会触发上述报错,换成其他类型引用则校验正常,实际触发点和Multiclassing无直接关联。
涉及文件配置
/src/swagger/schemas/combined.yml
Multiclassing: $ref: './multiclassing.yml' OptionSet: $ref: './common.yml#/option-set-model' Option: $ref: './common.yml#/option-model'
/src/swagger/schemas/multiclassing.yml
description: | `Multiclassing` type: object properties: prerequisites: description: List of prerequisites that must be met. type: array items: $ref: "./combined.yml#/Prerequisite" prerequisite_options: description: List of choices of prerequisites to meet for. type: array items: $ref: "./combined.yml#/Choice" proficiencies: description: "List of proficiencies available when multiclassing." type: array items: $ref: "./combined.yml#/APIReference" proficiency_choices: description: List of choices of proficiencies that are given when multiclassing. type: array items: $ref: "./combined.yml#/Choice"
/src/swagger/schemas/classes.yml
class-model: description: | `Class` allOf: - $ref: './combined.yml#/APIReference' - type: object properties: hit_die: description: 'Hit die of the class. (ex: 12 == 1d12).' type: number class_levels: description: URL of the level resource for the class. type: string multi_classing: $ref: './combined.yml#/Multiclassing' spellcasting: $ref: './combined.yml#/Spellcasting' spells: description: URL of the spell resource list for the class. type: string starting_equipment: description: List of equipment and their quantities all players of the class start with. type: array items: type: object properties: quantity: type: number equipment: $ref: './combined.yml#/APIReference' starting_equipment_options: description: List of choices of starting equipment. type: array items: $ref: './combined.yml#/Choice' proficiency_choices: description: List of choices of starting proficiencies. type: array items: $ref: './combined.yml#/Choice' proficiencies: description: List of starting proficiencies for all new characters of this class. type: array items: $ref: './combined.yml#/APIReference' saving_throws: description: Saving throws the class is proficient in. type: array items: $ref: './combined.yml#/APIReference' subclasses: description: List of all possible subclasses this class can specialize in. type: array items: $ref: './combined.yml#/APIReference'
/src/swagger/paths/classes.yml
class-multi-classing-path: get: summary: Get multiclassing resource for a class. tags: - Class parameters: - $ref: '../parameters/combined.yml#/class-index' responses: '200': description: OK content: application/json: schema: $ref: '../schemas/combined.yml#/Multiclassing' example: prerequisites: - ability_score: index: str name: STR url: '/api/ability-scores/str' minimum_score: 13 proficiencies: - index: shields name: Shields url: '/api/proficiencies/shields' - index: simple-weapons name: Simple Weapons url: '/api/proficiencies/simple-weapons' - index: martial-weapons name: Martial Weapons url: '/api/proficiencies/martial-weapons' proficiency_choices: []
/src/swagger/schemas/common.yml
option-model: description: | `Option` oneOf: - type: object properties: option_type: description: 'Type of option; determines other attributes.' type: string item: $ref: './combined.yml#/APIReference' - type: object properties: option_type: description: 'Type of option; determines other attributes.' type: string action_name: description: 'The name of the action.' type: string count: description: 'The number of times this action can be repeated if chosen.' type: number type: description: 'For attack options that can be melee, ranged, abilities, or thrown.' type: string - type: object properties: option_type: description: 'Type of option; determines other attributes.' type: string items: type: array items: $ref: './combined.yml#/Option' - type: object properties: option_type: description: 'Type of option; determines other attributes.' type: string choice: $ref: './combined.yml#/Choice' - type: object properties: option_type: description: 'Type of option; determines other attributes.' type: string string: description: 'The string.' type: string - type: object properties: option_type: description: 'Type of option; determines other attributes.' type: string desc: description: 'A description of the ideal.' type: string alignments: description: 'A list of alignments of those who might follow the ideal.' type: array items: $ref: './combined.yml#/APIReference' - type: object properties: option_type: description: 'Type of option; determines other attributes.' type: string count: description: 'Count' type: number of: $ref: './combined.yml#/APIReference' - type: object properties: option_type: description: 'Type of option; determines other attributes.' type: string ability_score: $ref: './combined.yml#/APIReference' minimum_score: description: 'The minimum score required to satisfy the prerequisite.' type: number - type: object properties: option_type: description: 'Type of option; determines other attributes.' type: string ability_score: $ref: './combined.yml#/APIReference' bonus: description: 'The bonus being applied to the ability score' type: number - type: object properties: option_type: description: 'Type of option; determines other attributes.' type: string name: description: 'Name of the breath' type: string dc: $ref: './combined.yml#/DC' damage: description: 'Damage dealt by the breath attack, if any.' type: array items: $ref: './combined.yml#/Damage' - type: object properties: option_type: description: 'Type of option; determines other attributes.' type: string damage_type: $ref: './combined.yml#/APIReference' damage_dice: description: 'Damage expressed in dice (e.g. "13d6").' type: string notes: description: 'Information regarding the damage.' type: string option-set-model: description: | `Option Set` oneOf: - type: object properties: option_set_type: description: 'Type of option set; determines other attributes.' type: string options_array: description: 'Array of options to choose from.' type: array items: $ref: './combined.yml#/Option' - type: object properties: option_set_type: description: 'Type of option set; determines other attributes.' type: string equipment_category: $ref: './combined.yml#/APIReference' - type: object properties: option_set_type: description: 'Type of option set; determines other attributes.' type: string resource_list: description: 'A reference (by URL) to a collection in the database.' type: string choice-model: description: | `Choice` type: object properties: desc: description: 'Description of the choice to be made.' type: string choose: description: 'Number of items to pick from the list.' type: number type: description: 'Type of the resources to choose from.' type: string from: $ref: './combined.yml#/OptionSet'
问题根因
别被报错信息误导,这是典型的跨文件循环引用+schema中转映射缺失导致的解析异常。swagger-cli的解析器在处理跨文件$ref链路遇到断链时,不会直接返回真正缺失的引用名,而是随机抛出解析过程中碰到的第一个顶层schema名称当错误信息,所以才会出现实际问题在Option/Choice引用链,却报Multiclassing不存在的迷惑现象。
具体问题点有两个:
combined.yml作为所有schema的统一中转出口,只映射了Multiclassing/OptionSet/Option三个定义,但所有文件里大量引用的Choice/Prerequisite/APIReference/Spellcasting/DC/Damage等定义都没有在combined.yml里加映射,解析链路走到这些未映射的引用时就会直接断链。- 存在循环引用:
common.yml里的option-model/option-set-model/choice-model互相依赖,又都通过combined.yml做路径中转,旧版本swagger-cli处理这类循环引用时,只要中转文件的映射不全,就会随机抛出token不存在的报错。
解决步骤
- 补全
combined.yml的所有schema映射,把所有跨文件引用到的顶层定义全部加进去,首先补上最直接缺失的Choice映射,其余缺失的定义按同样格式补全即可:
# 修正后的combined.yml示例 Multiclassing: $ref: './multiclassing.yml' OptionSet: $ref: './common.yml#/option-set-model' Option: $ref: './common.yml#/option-model' # 补上缺失的Choice映射 Choice: $ref: './common.yml#/choice-model' # 其余用到的Prerequisite/APIReference/Spellcasting/DC/Damage等定义,参照上述格式补全
- 确认文件名拼写:存放通用schema的文件实际名称必须是
common.yml,和所有$ref里写的路径保持一致,不要出现调试记录里的comman.yml这类拼写错误。 - 如果补全映射后还是报错,直接升级swagger-cli到最新版本,旧版本对跨文件循环引用的解析存在已知bug,升级后可以解决绝大多数随机报token不存在的问题:
npm install -g @apidevtools/swagger-cli@latest
- 后续校验时加上
--dereference参数做全量解引用,可以直接定位到真正断链的$ref路径,不会再被无关的顶层token报错误导:
swagger-cli validate src/swagger/swagger.yml --dereference
内容的提问来源于stack exchange,提问作者Anthony Bias
相关产品推荐
相关产品推荐

