{"record":{"id":"e54987341b208505","repo":"flipped-aurora/gin-vue-admin","slug":"cli-s-w","errorCode":null,"errorMessage":"读取 CLI 源码目录失败(%s): %w","messagePattern":"读取 CLI 源码目录失败\\((.+?)\\): %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/plugin/ai/service/sys_cli_build.go","lineNumber":126,"sourceCode":"\t}\n\tbinaryName += cliBinaryExt(goos)\n\tbinaryPath := filepath.Join(buildDir, binaryName)\n\n\tif err := runGoBuild(buildDir, binaryPath, goos, goarch); err != nil {\n\t\treturn \"\", nil, err\n\t}\n\tbinary, err := os.ReadFile(binaryPath)\n\tif err != nil {\n\t\treturn \"\", nil, err\n\t}\n\treturn binaryName, binary, nil\n}\n\n// copyCliSources 复制 gva 源码到编译目录，跳过测试文件和默认的 embedded.go。\nfunc copyCliSources(srcDir, destDir string) error {\n\tentries, err := os.ReadDir(srcDir)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"读取 CLI 源码目录失败(%s): %w\", srcDir, err)\n\t}\n\tfor _, entry := range entries {\n\t\tif entry.IsDir() {\n\t\t\tcontinue\n\t\t}\n\t\tname := entry.Name()\n\t\tif !strings.HasSuffix(name, \".go\") || strings.HasSuffix(name, \"_test.go\") {\n\t\t\tcontinue\n\t\t}\n\t\tif name == cliEmbeddedGoName {\n\t\t\tcontinue\n\t\t}\n\t\tdata, err := os.ReadFile(filepath.Join(srcDir, name))\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif err := os.WriteFile(filepath.Join(destDir, name), data, 0o644); err != nil {\n\t\t\treturn err","sourceCodeStart":108,"sourceCodeEnd":144,"githubUrl":"https://github.com/flipped-aurora/gin-vue-admin/blob/3136500ef380842b0eb6c4daa87c3f8a47fcf9e0/server/plugin/ai/service/sys_cli_build.go#L108-L144","documentation":"copyCliSources copies the gva CLI source directory (cliSourceDir) into the per-build temp directory, skipping tests and embedded.go. It first reads the source dir with os.ReadDir; if that fails, this error wrapping the OS error is returned. It means the embedded/reference source tree shipped with the deployment is missing or unreadable.","triggerScenarios":"cliSourceDir was not shipped (Docker image built without it), was deleted by a cleanup job, or the server process lacks read permission on it. Triggered from BuildCliBinary/BuildCliSkill via compileCliBinary.","commonSituations":"Packaging the binary alone without the server/resource directories; container images that exclude source assets; wrong working directory so the relative cliSourceDir resolves to a nonexistent path; restrictive file modes after extraction as root.","solutions":["Verify cliSourceDir exists and is readable by the server user (ls -la) and fix the deployment package","Check the server's working directory — if cliSourceDir is relative, an unexpected cwd breaks resolution; set an absolute path","Re-deploy including the CLI source assets in the image/artifact","Fix permissions (chown/chmod) if the dir exists but is unreadable"],"exampleFix":"// before (dockerfile)\nCOPY server/gva ./gva\n// after — include the CLI source dir\nCOPY server/gva ./gva\nCOPY server/resource/cli-source ./gva/resource/cli-source","handlingStrategy":"validation","validationCode":"if st, err := os.Stat(cliSourceDir); err != nil || !st.IsDir() {\n    return fmt.Errorf(\"CLI source dir %s missing or unreadable\", cliSourceDir)\n}","typeGuard":null,"tryCatchPattern":"bin, content, err := svc.BuildCliBinary(cli, manifest, goos, goarch)\nif err != nil {\n    if strings.Contains(err.Error(), \"读取 CLI 源码目录失败\") {\n        return nil, fmt.Errorf(\"deployment incomplete: CLI sources missing at %s\", cliSourceDir)\n    }\n    return err\n}","preventionTips":["Include CLI source assets in the deployment artifact/image","Use absolute paths for cliSourceDir or pin the service WorkingDirectory","Add a startup check that the source dir exists and is readable"],"tags":["go","filesystem","deployment","missing-files"],"backgroundTag":"missing-source-directory","analyzedSha":"3136500ef380842b0eb6c4daa87c3f8a47fcf9e0","analyzedAt":"2026-08-31T13:50:02.721Z","schemaVersion":2},"datasetVersion":"2026-08-31T19:17:28.585Z"}