{"record":{"id":"4d38c79e102f26aa","repo":"shadow1ng/fscan","slug":"target-file-not-specified","errorCode":null,"errorMessage":"Target file not specified","messagePattern":"Target file not specified","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"plugins/local/crontask.go","lineNumber":56,"sourceCode":"func (p *CronTaskPlugin) Scan(ctx context.Context, info *common.HostInfo, session *common.ScanSession) *plugins.Result {\n\tconfig := session.Config\n\tvar output strings.Builder\n\n\tif runtime.GOOS != \"linux\" {\n\t\treturn &plugins.Result{\n\t\t\tSuccess: false,\n\t\t\tOutput:  i18n.GetText(\"crontask_linux_only\"),\n\t\t\tError:   fmt.Errorf(\"%s\", i18n.Tr(\"unsupported_platform\", runtime.GOOS)),\n\t\t}\n\t}\n\n\t// 从config获取配置\n\tp.targetFile = config.PersistenceTargetFile\n\tif p.targetFile == \"\" {\n\t\treturn &plugins.Result{\n\t\t\tSuccess: false,\n\t\t\tOutput:  i18n.GetText(\"persistence_file_required\"),\n\t\t\tError:   fmt.Errorf(\"%s\", i18n.GetText(\"target_file_not_specified\")),\n\t\t}\n\t}\n\n\t// 检查目标文件是否存在\n\tif _, err := os.Stat(p.targetFile); os.IsNotExist(err) {\n\t\treturn &plugins.Result{\n\t\t\tSuccess: false,\n\t\t\tOutput:  i18n.Tr(\"target_file_not_exist\", p.targetFile),\n\t\t\tError:   err,\n\t\t}\n\t}\n\n\t// 检查crontab是否可用\n\tif _, err := exec.LookPath(\"crontab\"); err != nil {\n\t\treturn &plugins.Result{\n\t\t\tSuccess: false,\n\t\t\tOutput:  i18n.GetText(\"crontab_unavailable\"),\n\t\t\tError:   err,","sourceCodeStart":38,"sourceCodeEnd":74,"githubUrl":"https://github.com/shadow1ng/fscan/blob/95cc12e753bf43de7004e5aef42a9ffba3934303/plugins/local/crontask.go#L38-L74","documentation":"Scan of the crontask plugin requires config.PersistenceTargetFile — the path of the script to persist via cron. When it is empty, the plugin returns a failed Result with this error, because it cannot proceed without knowing which file to install into a cron job.","triggerScenarios":"Calling Scan with a Config in which PersistenceTargetFile is \"\" (zero value / omitted in config file / CLI flag not passed).","commonSituations":"Config struct built programmatically with the field forgotten; YAML/JSON key typo (e.g. persist_target vs PersistenceTargetFile) so it never deserializes; running the plugin without the required CLI flag.","solutions":["Set Config.PersistenceTargetFile to the absolute path of the script to persist before calling Scan.","Fix key-name mismatches in your config file/struct tags so the field deserializes.","Check the field in the caller and skip or error out early with a clearer message.","Require the corresponding CLI flag at startup if the value ultimately comes from argv."],"exampleFix":"// before\ncfg := plugins.Config{Name: \"crontask\"}\n// after\ncfg := plugins.Config{Name: \"crontask\", PersistenceTargetFile: \"/opt/agent/agent.sh\"}","handlingStrategy":"validation","validationCode":"if strings.TrimSpace(cfg.PersistenceTargetFile) == \"\" {\n    return errors.New(\"PersistenceTargetFile is required for crontask plugin\")\n}\nif _, err := os.Stat(cfg.PersistenceTargetFile); err != nil {\n    return fmt.Errorf(\"target file missing: %w\", err)\n}","typeGuard":"func crontaskConfigReady(cfg plugins.Config) bool {\n    return strings.TrimSpace(cfg.PersistenceTargetFile) != \"\"\n}","tryCatchPattern":"res := plugin.Scan(ctx, cfg)\nif !res.Success && res.Error != nil && strings.Contains(res.Error.Error(), \"Target file not specified\") {\n    return fmt.Errorf(\"crontask misconfigured: %w\", res.Error)\n}","preventionTips":["Always set PersistenceTargetFile from a validated, absolute path.","Verify struct tags/JSON keys match so the field actually deserializes.","Stat the file before invoking the plugin to fail earlier with clearer context."],"tags":["persistence","config","cron"],"backgroundTag":"missing-required-config-field","analyzedSha":"95cc12e753bf43de7004e5aef42a9ffba3934303","analyzedAt":"2026-09-06T17:07:30.094Z","contentChangedAt":"2026-09-06T17:07:30.094Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}