While deploying a client Spring Boot web app as a Linux service, I ran into the Exec format error
caused by a missing #!/bin/bash
line in the startup script. Once I added the shebang, removed unnecessary sudo
, and ensured the script was executable, the service started cleanly. I then enhanced it for production by adding logging, a JAR existence check, JVM memory settings, and automatic restarts. Now the service is more reliable, easier to debug, and resilient against failures.
springboot.service: Failed to execute command: Exec format error
springboot.service: Failed at step EXEC spawning /home/ubuntu/spring-start.sh: Exec format error
I recently hit this exact issue while deploying my Spring Boot web app as a Linux service.
At first, it was frustrating because the error wasn’t very descriptive but once I figured it out, it turned out to be a very simple fix.
Let me walk you through my original code, why it failed, and how I improved it for production use.
Original Service File and Script
Here’s what I started with.
springboot.service
[Unit]
Description=My Webapp Java REST Service
[Service]
User=ubuntu
WorkingDirectory=/home/ubuntu
# Bash script to start the Spring Boot JAR
ExecStart=/home/ubuntu/spring-start.sh
SuccessExitStatus=143
TimeoutStopSec=10
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
spring-start.sh
sudo java -jar "/home/ubuntu/FirstWebAppWithoutDB.jar"
Setup Commands
chmod u+x spring-start.sh
sudo systemctl daemon-reload
sudo systemctl enable springboot.service
sudo systemctl start springboot
sudo systemctl status springboot
Why I Got the Exec format error
After running systemctl start springboot
, I was greeted with:
springboot.service: Failed to execute command: Exec format error
springboot.service: Failed at step EXEC spawning /home/ubuntu/spring-start.sh: Exec format error
The cause? My script was missing the shebang line.
Linux didn’t know what program should interpret the script. When you run something from the terminal manually, your shell interprets it automatically, but systemd
needs explicit instructions.
The Fix Code
I fixed it by adding the shebang at the very top of the script and making a couple of other adjustments.
spring-start.sh
(fixed)
#!/bin/bash
java -jar "/home/ubuntu/FirstWebAppWithoutDB.jar"
Key fixes:
- Added
#!/bin/bash
— tells Linux to use Bash to execute the file. - Removed
sudo
—systemd
already runs this underUser=ubuntu
. - Double-checked execution permissions:
chmod +x /home/ubuntu/spring-start.sh
Adding More Practical Functionality
Once I got it working, I decided to make it production-friendly.
Here’s what I added:
- Logging output so I can check startup errors later.
- File existence check to avoid silent failures.
- JVM memory options for better performance.
- Graceful error handling for a cleaner exit.
spring-start.sh
(improved)
#!/bin/bash
APP_PATH="/home/ubuntu/FirstWebAppWithoutDB.jar"
LOG_FILE="/home/ubuntu/springboot.log"
# Check if JAR exists
if [[ ! -f "$APP_PATH" ]]; then
echo "$(date) - ERROR: JAR file not found at $APP_PATH" >> "$LOG_FILE"
exit 1
fi
echo "$(date) - Starting Spring Boot application..." >> "$LOG_FILE"
# Run the application with JVM options
exec java -Xms512m -Xmx1024m -jar "$APP_PATH" >> "$LOG_FILE" 2>&1
Updated Service File for Logging
I also updated my service file so that systemd
sends logs directly to my application log file.
springboot.service
(updated)
[Unit]
Description=My Webapp Java REST Service
After=network.target
[Service]
User=ubuntu
WorkingDirectory=/home/ubuntu
ExecStart=/home/ubuntu/spring-start.sh
StandardOutput=append:/home/ubuntu/springboot.log
StandardError=append:/home/ubuntu/springboot.log
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
Final Thought
A missing #!/bin/bash
line caused me hours of frustration, but fixing it not only solved the Exec format error
it also pushed me to improve my Spring Boot service. Now it starts cleanly, logs for easier debugging, checks for missing JAR files, and restarts automatically if something goes wrong.