{"record":{"id":"63d2d39efe0d045d","repo":"jdx/mise","slug":"service-unit-name-must-set-a-non-empty-exec-s","errorCode":null,"errorMessage":"service unit '{name}' must set a non-empty `exec_start`","messagePattern":"service unit '(.+?)' must set a non-empty `exec_start`","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/system/systemd.rs","lineNumber":176,"sourceCode":"        if !valid_name(&name) {\n            bail!(\"unit name '{name}' must contain only letters, numbers, '.', '_', '-', or '@'\");\n        }\n        let is_timer = config.on_boot_sec.is_some()\n            || config.on_unit_active_sec.is_some()\n            || config.on_unit_inactive_sec.is_some()\n            || config.on_calendar.is_some()\n            || config.randomized_delay_sec.is_some()\n            || config.accuracy_sec.is_some()\n            || config.persistent.is_some()\n            || config.unit.is_some();\n        let kind = if is_timer {\n            SystemdUnitKind::Timer\n        } else {\n            SystemdUnitKind::Service\n        };\n        let exec_start = config.exec_start.map(|s| s.trim().to_string());\n        if kind == SystemdUnitKind::Service && exec_start.as_deref().is_none_or(str::is_empty) {\n            bail!(\"service unit '{name}' must set a non-empty `exec_start`\");\n        }\n        if kind == SystemdUnitKind::Timer {\n            let service_only_fields = [\n                (exec_start.is_some(), \"exec_start\"),\n                (config.service_type.is_some(), \"type\"),\n                (config.remain_after_exit.is_some(), \"remain_after_exit\"),\n                (config.exec_stop.is_some(), \"exec_stop\"),\n                (config.timeout_start_sec.is_some(), \"timeout_start_sec\"),\n                (config.timeout_stop_sec.is_some(), \"timeout_stop_sec\"),\n                (config.no_new_privileges.is_some(), \"no_new_privileges\"),\n                (config.private_tmp.is_some(), \"private_tmp\"),\n                (!config.environment.is_empty(), \"environment\"),\n                (!config.environment_file.is_empty(), \"environment_file\"),\n                (config.nice.is_some(), \"nice\"),\n                (config.umask.is_some(), \"umask\"),\n                (config.working_directory.is_some(), \"working_directory\"),\n                (config.restart.is_some(), \"restart\"),\n                (config.restart_sec.is_some(), \"restart_sec\"),","sourceCodeStart":158,"sourceCodeEnd":194,"githubUrl":"https://github.com/jdx/mise/blob/533346cc374382b41ec5ff70536252b2e96e725c/src/system/systemd.rs#L158-L194","documentation":"from_toml requires that every service-kind systemd unit defines exec_start with non-empty (after trimming whitespace) content, since a systemd service without ExecStart is invalid. Timer units are exempt — they only need a scheduling directive.","triggerScenarios":"Defining a service unit in mise.toml without an exec_start key, or with exec_start = \"\" or whitespace-only value, then loading the systemd config through SystemdRequest::from_toml.","commonSituations":"Writing a timer entry but leaving service fields out of a service block; commenting out exec_start during debugging; copy-pasting a timer template for a service; intending a timer but not setting any schedule field so it defaults to Service kind.","solutions":["Add a non-empty exec_start to the unit's TOML config (e.g. exec_start = \"/usr/bin/myapp --serve\")","If the entry is meant to be a timer, add a schedule key (on_boot_sec, on_calendar, etc.) so it is classified as a Timer","Remove the unit entry entirely if it is unused","Trim stray whitespace-only values from exec_start"],"exampleFix":"# before (mise.toml)\n[systemd.\"myapp.service\"]\n# exec_start commented out\n# after\n[systemd.\"myapp.service\"]\nexec_start = \"/usr/local/bin/myapp --serve\"","handlingStrategy":"validation","validationCode":"// pre-validate a service entry before writing config\nif schedule_keys.is_empty() && exec_start.as_deref().map(str::trim).unwrap_or(\"\").is_empty() {\n    bail!(\"service needs a non-empty exec_start (or schedule keys to be a timer)\");\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always pair every service unit with an exec_start line in the TOML block","Don't leave exec_start = \"\" as a placeholder — remove the whole entry instead","Remember timer-kind detection depends on schedule keys; add them if you meant a timer"],"tags":["systemd","validation","missing-field","config"],"backgroundTag":"empty-required-field","analyzedSha":"533346cc374382b41ec5ff70536252b2e96e725c","analyzedAt":"2026-09-17T13:35:38.149Z","contentChangedAt":"2026-09-17T13:35:38.149Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}