Failures, on_end and limits
A build action is part of your build. When it fails, the build fails, and the log tells you which script, why, and the last lines it printed. on_end is the one hook that always runs, so it is where you report the result.
When a script fails
Any error in a script fails the build. That includes an uncaught exception, a syntax error, a missing import, a non-zero exit code, a crash, and running too long. Output on stderr with exit code 0 counts as success.
Where the failure shows
- Your script's full output in the build log under build action <hook>, including the whole Python traceback or Node stack trace.
- The build action <hook> step marked failed on the build page.
- A summary at the end of the log that repeats the last lines of your script's error output:
=== BUILD ACTION FAILED: pre_build (.dsl/build_actions/pre_build.py) === reason: exited with code 1 runtime: python 3.14.7 cwd: <project folder> duration: 4.2 s last lines of stderr: Traceback (most recent call last): File ".../.dsl/build_actions/pre_build.py", line 12, in <module> FileNotFoundError: [Errno 2] No such file or directory: 'Assets/Gen/config.json'
Reading the build log and its steps is covered in Your first build.
Fail a build on purpose
Exit non-zero: sys.exit(1) in Python or process.exit(1) in Node. Use it for checks that should stop a build, such as a missing asset or a version that does not match.
Platform faults
Reporting results with on_end
on_end always runs last and is told how the build went:
| Variable | Value |
|---|---|
DSL_BUILD_RESULT | success, failed, or exception (a platform error) |
DSL_FAILED_PHASE | The step that failed, e.g. build or build action pre_build |
DSL_FAILURE_MESSAGE | The one-line reason |
This on_end.py posts the result to a chat webhook whose URL is stored as the secret CHAT_WEBHOOK_URL (see Secrets in build actions):
# .dsl/build_actions/on_end.py - post the result to a chat webhook import json, os, urllib.request secrets = json.load(open(os.environ["DSL_SECRETS_FILE"])) result = os.environ["DSL_BUILD_RESULT"] text = f'{os.environ["DSL_PROJECT"]} {os.environ["DSL_VERSION"]}.{os.environ["DSL_BUILD_NUMBER"]} ({os.environ["DSL_CONFIGURATION"]}): {result}' if result != "success": text += f' - {os.environ.get("DSL_FAILED_PHASE", "")}: {os.environ.get("DSL_FAILURE_MESSAGE", "")}' req = urllib.request.Request(secrets["CHAT_WEBHOOK_URL"], data=json.dumps({"text": text}).encode(), headers={"Content-Type": "application/json"}) urllib.request.urlopen(req, timeout=30)
on_end does not run when a build is canceled or interrupted by maintenance.
Limits
| Limit | Value |
|---|---|
| Time per script | 30 minutes |
| No output | 15 minutes: a script that prints nothing for that long is stopped |
| Scripts per hook | 1 |
A script stopped by a limit fails the build, and the log names the limit it hit. For long work, split it across hooks or print progress as you go.
Something out of date or unclear? Email support@devstreamlabs.com.