Fix “crontab: tmp/tmp.X: Operation not permitted” Error in macOS Mojave


1 views

Since macOS Mojave (10.14), Apple implemented stricter System Integrity Protection (SIP) that affects certain system directories including /private/var/at. This manifests when trying to edit crontabs:

$ crontab -e
crontab: tmp/tmp.XXXXXX: Operation not permitted

The issue stems from Mojave's new privacy protections. Even with sudo, you'll notice:

$ sudo touch /private/var/at/test
touch: /private/var/at/test: Operation not permitted

This occurs because /private/var/at is now protected by SIP's filesystem restrictions, similar to how /usr/bin is protected.

Option 1: Temporary SIP Disable (Not Recommended)

While you could disable SIP, this compromises system security:

# Reboot into Recovery Mode (Cmd+R)
# Open Terminal
csrutil disable
reboot

Option 2: Approved Mojave Workaround

Use macOS's built-in launchd instead. Create a plist:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Label</key>
    <string>com.example.myjob</string>
    <key>ProgramArguments</key>
    <array>
        <string>/path/to/your/script.sh</string>
    </array>
    <key>StartCalendarInterval</key>
    <dict>
        <key>Hour</key>
        <integer>2</integer>
        <key>Minute</key>
        <integer>0</integer>
    </dict>
</dict>
</plist>

Load it with:

launchctl load ~/Library/LaunchAgents/com.example.myjob.plist

Option 3: Manual Crontab Editing (Advanced)

For those who absolutely need classic crontab functionality:

# 1. Create temp file
TMPFILE=$(mktemp /tmp/crontab.XXXXXX)

# 2. Export existing crontab
crontab -l > $TMPFILE

# 3. Edit manually
vi $TMPFILE

# 4. Import back (using sudo -E to preserve environment)
sudo -E crontab $TMPFILE

# 5. Cleanup
rm $TMPFILE

• Mojave's privacy protections extend to many system directories
• Apple is gradually deprecating traditional Unix tools in favor of launchd
• Consider using /usr/local/bin for custom scripts to avoid permission issues


Since macOS Mojave (10.14), Apple implemented stricter System Integrity Protection (SIP) that affects several system directories, including /private/var/at. When you attempt to modify crontab entries, the system prevents writing temporary files to this protected location.

First, let's verify the current permissions and SIP status:

# Check SIP status
csrutil status

# Examine directory permissions
ls -laO /private/var/at
ls -laOd /private/var/at

Method 1: Temporary Disable SIP (Not Recommended for Production)

  1. Reboot into Recovery Mode (Command+R during startup)
  2. Open Terminal from Utilities menu
  3. Run: csrutil disable
  4. Reboot and test crontab
  5. Re-enable SIP afterward: csrutil enable

Method 2: Alternative crontab Directory (Recommended)

Create a custom crontab directory with proper permissions:

sudo mkdir -p /usr/local/var/cron
sudo chown $(whoami) /usr/local/var/cron
export CRON_TMPDIR=/usr/local/var/cron
crontab -e

Make this permanent by adding to your shell profile:

echo 'export CRON_TMPDIR=/usr/local/var/cron' >> ~/.zshrc

Method 3: Using launchd Instead (macOS Native Alternative)

Create a plist file for your cron job:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Label</key>
    <string>com.example.myjob</string>
    <key>ProgramArguments</key>
    <array>
        <string>/path/to/your/script.sh</string>
    </array>
    <key>StartCalendarInterval</key>
    <dict>
        <key>Hour</key>
        <integer>2</integer>
        <key>Minute</key>
        <integer>0</integer>
    </dict>
</dict>
</plist>

Load it with:

launchctl load ~/Library/LaunchAgents/com.example.myjob.plist
  • Check Console logs for detailed error messages
  • Verify Terminal has Full Disk Access in System Preferences
  • Consider creating a dedicated user for cron jobs with appropriate permissions