canonical / canonical/cloud-init
error handling issue: cloud-init produces a traceback on invalid user configuration
- Dominant language
- Python
- Stars
- 3.8k
- Forks
- 1.1k
- Avg merge
- 2d 23h
- Merged PRs (30d)
- 18
Description
# Bug report
`_maybe_set_hostname()` in `cloudinit/cmd/main.py` calls `util.get_hostname_fqdn(init.cfg, cloud, metadata_only=True)` before entering its only `try`/`except` block (that block guards just the later `cc_set_hostname.handle(...)` call). `get_hostname_fqdn()` in `cloudinit/util.py` then does `if "hostname" in cfg and cfg["hostname"].find(".") > 0:` with no type check or `str()` cast on `cfg["hostname"]`. If the merged config's hostname value is ever a non-string (e.g. an all-digit value that gets interpreted as an int somewhere upstream instead of staying a string), this raises `AttributeError: 'int' object has no attribute 'find'` — and because the call happens outside the guarded block, the exception propagates uncaught out of `main_init`, killing the entire `init-local` stage.
On a NoCloud/local-datasource boot (e.g. Raspberry Pi OS via Raspberry Pi Imager), this cascades to fail `cloud-init-local.service`, `cloud-init-network.service`, `cloud-config.service`, and `cloud-final.service` on every subsequent boot — `write_files`, `runcmd`, and (critically) network-config rendering never run again until the underlying config is fixed. On a headless device this silently and permanently breaks network provisioning, with no user-facing error beyond the log file.
## Steps to reproduce the problem
1. Set a purely-numeric string as the hostname in `user-data`:
#cloud-config
hostname: "123456"
2. Boot with this cloud-config via the NoCloud datasource (`dsmode: local`).
3. Inspect `/var/log/cloud-init.log` — `init-local` fails with the traceback below, and `cloud-init status --long` reports failure for all stages.
Reproduced specifically with Raspberry Pi Imager's cloud-init-based headless setup (`user-data` + `meta-data` + `network-config` seeded via `file:///boot/firmware`), but the crash is in generic `cloudinit/util.py` and `cloudinit/cmd/main.py` code, not anything Raspberry Pi OS-specific — it should reproduce identically on any NoCloud (or other datasource) boot where a numeric hostname reaches `get_hostname_fqdn()`.
## Environment details
- Cloud-init version: 25.2
- Operating System Distribution: Raspberry Pi OS (Debian 13 "Bookworm" based), aarch64
- Cloud provider, platform or installer type: Raspberry Pi Imager (NoCloud datasource, `dsmode: local`, seeded from `file:///boot/firmware`)
## cloud-init logs
2026-08-14 18:26:13,103 - main.py[ERROR]: failed stage init-local
Traceback (most recent call last):
File "/usr/lib/python3/dist-packages/cloudinit/cmd/main.py", line 963, in status_wrapper
ret = functor(name, args)
File "/usr/lib/python3/dist-packages/cloudinit/cmd/main.py", line 591, in main_init
_maybe_set_hostname(init, stage="local", retry_stage="network")
File "/usr/lib/python3/dist-packages/cloudinit/cmd/main.py", line 1046, in _maybe_set_hostname
(hostname, _fqdn, _) = util.get_hostname_fqdn(init.cfg, cloud, metadata_only=True)
File "/usr/lib/python3/dist-packages/cloudinit/util.py", line 1224, in get_hostname_fqdn
if "hostname" in cfg and cfg["hostname"].find(".") > 0:
AttributeError: 'int' object has no attribute 'find'
failed run of stage init-local
------------------------------------------------------------
systemd[1]: cloud-init-local.service: Main process exited, code=exited, status=1/FAILURE
systemd[1]: cloud-init-local.service: Failed with result 'exit-code'.
systemd[1]: Failed to start cloud-init-local.service - Cloud-init: Local Stage (pre-network).
systemd[1]: cloud-init-network.service: Main process exited, code=exited, status=1/FAILURE
systemd[1]: cloud-init-network.service: Failed with result 'exit-code'.
systemd[1]: Failed to start cloud-init-network.service - Cloud-init: Network Stage.
systemd[1]: Failed to start cloud-config.service - Cloud-init: Config Stage.
systemd[1]: Failed to start cloud-final.service - Cloud-init: Final Stage.
Same traceback recurs identically on every boot from the point a numeric hostname is first consumed onward (confirmed across 20+ boots spanning several days on the reporter's device); the very first boot instead hit the same underlying `AttributeError`, but through the module-pipeline call path (`cc_set_hostname` under `modules.py`), where it is caught and logged only as a `WARNING` rather than aborting the stage:
handlers.py[DEBUG]: finish: init-local/config-set_hostname: FAIL: running config-set_hostname with frequency once-per-instance
log_util.py[WARNING]: Running module set_hostname () failed
Suggested fix: either `str(cfg["hostname"]).find(".")` (and equivalent casts elsewhere in `get_hostname_fqdn`) in `cloudinit/util.py`, or move the `util.get_hostname_fqdn(...)` call in `_maybe_set_hostname` inside the existing `try`/`except` block so it fails as gracefully as the `cc_set_hostname.handle(...)` call right below it.
Contributor guide
Research direction
Start with get_hostname_fqdn in cloudinit/util.py and _maybe_set_hostname in cloudinit/cmd/main.py, following the traceback and existing try/except boundary. Reproduce with the NoCloud configuration described in the issue, then verify that a numeric hostname no longer produces an uncaught traceback or prevents later cloud-init stages from running.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- infrastructure
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 75/100