jdx/mise · error
the embedded notification helper is not Developer ID signed
Error message
the embedded notification helper is not Developer ID signed
What it means
On macOS, mise shows notifications through an embedded helper app bundle that must be signed with a Developer ID (and contain the expected icon/signature resources). notification() refuses to proceed when the checked bundle fails the release_signed() probe, because unsigned helpers are killed by notification infrastructure (especially Gatekeeper/notarization rules).
Solutions
- Install an official mise release (Developer ID signed) via the recommended installer or package manager instead of a locally built binary.
- Re-build/obtain the helper with a valid Developer ID Application certificate: `codesign --sign "Developer ID Application: <team>"`.
- Verify the signature with `codesign -dv --verbose=4 <path>/mise.app` and re-deploy the correct bundle.
- Disable notifications from mise if unsigned local builds are required (avoid the notify path).
Example fix
// before (local build) cargo build --release # helper ad-hoc signed -> error // after # install official signed release curl https://mise.run | sh # or sign the helper codesign --force --sign "Developer ID Application: YOURTEAM" mise.app
Defensive patterns
Strategy: fallback
Validate before calling
const { execSync } = require('child_process');
export function isDeveloperIdSigned(appPath: string): boolean {
try {
const out = execSync(`codesign -dv "${appPath}" 2>&1`).toString();
return /Authority=Developer ID Application/.test(out);
} catch {
return false;
}
} Type guard
function hasCodeSignature(app: string): boolean {
return require('fs').existsSync(`${app}/Contents/_CodeSignature/CodeResources`);
} Try / catch
try {
await notify(title, body);
} catch (e) {
if (/not Developer ID signed/.test(String(e))) {
logger.warn('notifications unavailable for unsigned local builds');
} else throw e;
} Prevention
- Use official signed mise releases on macOS
- Re-sign locally built helper bundles with a Developer ID certificate
- Verify with `codesign -dv` before packaging
When it happens
Trigger: Requesting a macOS notification when the helper app at Contents/MacOS / mise.icns / _CodeSignature checks pass structurally but the code signature is not a Developer ID signature — e.g. running a self-built or ad-hoc-signed mise, or a tampered helper bundle.
Common situations: Developer built mise from source and its embedded app is ad-hoc signed; the helper bundle was rebuilt locally losing the Developer ID signature; a packaged distribution stripped or re-signed the embedded app with a non-Developer ID identity.
Understand the failure class
Background: "not installed", "pip install", "required for": how missing-dependency errors surface across open-source libraries — this error's family across 34 libraries.
Related errors
- another process is installing the mise notification helper
- macOS binary signature verification failed (invalid…
- app target is outside an allowed Applications directory
- [bootstrap.macos.dock].apps: expected a path relative to…
- [bootstrap.macos.dock].apps: expected an absolute or ~/…
AI-assisted analysis of jdx/mise@533346cc37 (2026-09-17).
Data as JSON: /api/errors/4e28717ebd31fd79.
Report an issue: GitHub.
Appendix: source
Thrown at src/system/history/notify/macos.rs:51
// running helper. The bundle identifier remains stable across versions.
let fingerprint = crate::hash::hash_to_str(&(HELPER, INFO, ICON, CODE_RESOURCES));
root.join(fingerprint).join("mise.app")
}
fn executable(app: &Path) -> PathBuf {
app.join("Contents/MacOS/mise-notify")
}
fn complete(app: &Path) -> bool {
executable(app).is_file()
&& app.join("Contents/Info.plist").is_file()
&& app.join("Contents/Resources/mise.icns").is_file()
&& app.join("Contents/_CodeSignature/CodeResources").is_file()
}
pub(super) fn notification(title: &str, body: &str) -> Result<Command> {
if !release_signed() {
bail!("the embedded notification helper is not Developer ID signed");
}
let app = ensure_app(&crate::dirs::DATA.join("notifications"))?;
Ok(notification_command(&app, title, body))
}
fn notification_command(app: &Path, title: &str, body: &str) -> Command {
let mut command = Command::new(executable(app));
command.args([title, body]);
command
}
fn ensure_app(root: &Path) -> Result<PathBuf> {
let app = app_path(root);
if complete(&app) {
return Ok(app);
}
crate::file::create_dir_all(root)?;
let mut lock = fslock::LockFile::open(&root.join("install.lock"))?;View on GitHub (pinned to 533346cc37)