{"record":{"id":"a2359eff98411ff8","repo":"alibaba/nacos","slug":"parameter-missing-a2359e","errorCode":"PARAMETER_MISSING","errorMessage":"Required parameter 'skillName' when basedOnVersion is set","messagePattern":"Required parameter 'skillName' when basedOnVersion is set","errorType":"exception","errorClass":"NacosApiException","httpStatus":400,"severity":"error","filePath":"ai/src/main/java/com/alibaba/nacos/ai/form/skills/admin/SkillDraftCreateForm.java","lineNumber":60,"sourceCode":"    \n    private String commitMsg;\n    \n    /**\n     * Parsed skill for create-draft after {@link #prepareCreateDraftRequest()}; not part of the serialized form.\n     */\n    private transient Skill resolvedInitialSkill;\n    \n    /**\n     * The request form allow user create a new craft from current version. So if {@code basedOnVersion} is set,\n     * {@code skillCard} will be ignored, and {@code skillName} is required. Otherwise, means users create a new skill,\n     * so {@code skillCard} is required and {@code skillName} is ignored.\n     */\n    @Override\n    public void validate() throws NacosApiException {\n        fillDefaultNamespaceId();\n        if (StringUtils.isNotBlank(basedOnVersion)) {\n            if (StringUtils.isEmpty(getSkillName())) {\n                throw new NacosApiException(NacosException.INVALID_PARAM,\n                    ErrorCode.PARAMETER_MISSING,\n                    \"Required parameter 'skillName' when basedOnVersion is set\");\n            }\n            return;\n        }\n        super.validate();\n    }\n    \n    /**\n     * Validates this request, normalizes {@link #setSkillName(String)} when the name only appears inside\n     * {@code skillCard}, and caches the parsed skill for {@link #getResolvedInitialSkillOrNull()}.\n     * <p>\n     * Console and admin controllers must invoke this before {@code SkillProxy} / {@code SkillHandler}; handlers then\n     * only forward to service or remote client without repeating validation.\n     * </p>\n     */\n    public void prepareCreateDraftRequest() throws NacosApiException {\n        validate();","sourceCodeStart":42,"sourceCodeEnd":78,"githubUrl":"https://github.com/alibaba/nacos/blob/9b989acdf181d00898f2e8839257bb2b2a3cefe3/ai/src/main/java/com/alibaba/nacos/ai/form/skills/admin/SkillDraftCreateForm.java#L42-L78","documentation":"SkillDraftCreateForm.validate() implements a fork path: when `basedOnVersion` is set (non-blank), the request creates a new draft FROM an existing published version, so `skillCard` is ignored and `skillName` becomes mandatory to identify the source skill. A blank skillName in this fork mode fails with PARAMETER_MISSING. When basedOnVersion is absent, it falls through to super.validate() which requires skillCard instead.","triggerScenarios":"Calling create-draft with `basedOnVersion` set (e.g. `1.0.0`) but `skillName` blank. Common when forking: the client assumes the server knows which skill from context, but forking is cross-version of a NAMED skill.","commonSituations":"Frontend 'fork' button that sends only the source version and target version, omitting which skill to fork; assuming skillName is implied by namespace; confusion between create-new (skillCard required) and fork (skillName required) modes.","solutions":["When forking (basedOnVersion set), always include `skillName` of the skill to fork from.","If you actually want to create a brand-new skill, remove `basedOnVersion` and send `skillCard` instead.","Double-check the fork UI populates skillName from the source skill row."],"exampleFix":"// before\n{\"basedOnVersion\":\"1.0.0\",\"targetVersion\":\"1.1.0\"}\n// after\n{\"skillName\":\"my-skill\",\"basedOnVersion\":\"1.0.0\",\"targetVersion\":\"1.1.0\"}","handlingStrategy":"validation","validationCode":"// Fork mode: basedOnVersion set => skillName required\nif (basedOnVersion != null && !basedOnVersion.isBlank()\n    && (skillName == null || skillName.isEmpty())) {\n    throw new IllegalArgumentException(\"skillName is required when forking via basedOnVersion\");\n}","typeGuard":"// TypeScript\nconst forkRequestValid = (r: {basedOnVersion?: string; skillName?: string}): boolean =>\n  !r.basedOnVersion || !!r.skillName?.trim();","tryCatchPattern":"try {\n    form.validate();\n} catch (NacosApiException e) {\n    // fork mode missing skillName — populate from the source skill\n}","preventionTips":["In the fork UI, pre-fill skillName from the source skill row.","Document the two create-draft modes clearly: fork (basedOnVersion+skillName) vs new (skillCard).","Add an integration test covering both modes."],"tags":["validation","skill-api","required-field","draft","forking","conditional-validation"],"backgroundTag":null,"analyzedSha":"9b989acdf181d00898f2e8839257bb2b2a3cefe3","analyzedAt":"2026-08-14T07:17:31.569Z","schemaVersion":2},"datasetVersion":"2026-08-14T10:17:34.591Z"}