{"record":{"id":"15956340a5894b0a","repo":"flipped-aurora/gin-vue-admin","slug":"error-159563","errorCode":null,"errorMessage":"脚本已存在","messagePattern":"脚本已存在","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/service/system/sys_skills.go","lineNumber":284,"sourceCode":"\nfunc (s *SkillsService) CreateScript(_ context.Context, req request.SkillScriptCreateRequest) (string, string, error) {\n\tif !isSafeName(req.Skill) {\n\t\treturn \"\", \"\", errors.New(\"技能名称不合法\")\n\t}\n\tfileName, lang, err := buildScriptFileName(req.FileName, req.ScriptType)\n\tif err != nil {\n\t\treturn \"\", \"\", err\n\t}\n\tif lang == \"\" {\n\t\treturn \"\", \"\", errors.New(\"脚本类型不支持\")\n\t}\n\tskillDir, err := s.ensureSkillDir(req.Tool, req.Skill)\n\tif err != nil {\n\t\treturn \"\", \"\", err\n\t}\n\tfilePath := filepath.Join(skillDir, \"scripts\", fileName)\n\tif _, err := os.Stat(filePath); err == nil {\n\t\treturn \"\", \"\", errors.New(\"脚本已存在\")\n\t}\n\tif err := os.MkdirAll(filepath.Dir(filePath), os.ModePerm); err != nil {\n\t\treturn \"\", \"\", err\n\t}\n\tcontent := scriptTemplate(lang)\n\tif err := os.WriteFile(filePath, []byte(content), 0644); err != nil {\n\t\treturn \"\", \"\", err\n\t}\n\treturn fileName, content, nil\n}\n\nfunc (s *SkillsService) GetScript(_ context.Context, req request.SkillFileRequest) (string, error) {\n\treturn s.readSkillFile(req.Tool, req.Skill, \"scripts\", req.FileName)\n}\n\nfunc (s *SkillsService) SaveScript(_ context.Context, req request.SkillFileSaveRequest) error {\n\treturn s.writeSkillFile(req.Tool, req.Skill, \"scripts\", req.FileName, req.Content)\n}","sourceCodeStart":266,"sourceCodeEnd":302,"githubUrl":"https://github.com/flipped-aurora/gin-vue-admin/blob/3136500ef380842b0eb6c4daa87c3f8a47fcf9e0/server/service/system/sys_skills.go#L266-L302","documentation":"CreateScript checks os.Stat on <skillDir>/scripts/<fileName>; if the file already exists (stat succeeds) it returns \"脚本已存在\" instead of overwriting. The service never clobbers existing scripts.","triggerScenarios":"Calling CreateScript with a fileName whose normalized result (base + language extension) already exists in the skill's scripts/ directory, e.g. creating \"run\" with type sh when run.sh exists.","commonSituations":"Retrying a create after a previous success; creating a script whose name collides with an extension-stripped existing file; concurrent creation by two users; duplicate names in a synced skill copied across tools.","solutions":["Pick a different file name","If you want to change the existing script, use the SaveScript API to overwrite its content instead of CreateScript","Delete the existing script file first if it is no longer needed"],"exampleFix":"// before (fails: run.sh exists)\nCreateScript({skill: \"deploy\", fileName: \"run\", scriptType: \"sh\"})\n// after (overwrite content instead)\nSaveScript({skill: \"deploy\", fileName: \"run.sh\", content: newContent})","handlingStrategy":"try-catch","validationCode":"target := filepath.Join(skillDir, \"scripts\", fileName)\nif _, err := os.Stat(target); err == nil { /* exists: switch to save/update flow */ }","typeGuard":null,"tryCatchPattern":"err := svc.CreateScript(ctx, req)\nif err != nil && err.Error() == \"脚本已存在\" {\n    // fall back to SaveScript to overwrite content\n    return svc.SaveScript(ctx, request.SkillFileSaveRequest{Tool: req.Tool, Skill: req.Skill, FileName: fileName, Content: newContent})\n}\nreturn err","preventionTips":["List existing scripts (via Detail) before creating","Remember the extension is appended from scriptType — check base-name collisions","Use SaveScript for updates; CreateScript only for new files"],"tags":["filesystem","conflict","go"],"backgroundTag":"file-already-exists","analyzedSha":"3136500ef380842b0eb6c4daa87c3f8a47fcf9e0","analyzedAt":"2026-08-31T13:50:02.721Z","schemaVersion":2},"datasetVersion":"2026-08-31T19:17:28.585Z"}