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
-
Set a purely-numeric string as the hostname in user-data:
#cloud-config
hostname: "123456"
-
Boot with this cloud-config via the NoCloud datasource (dsmode: local).
-
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 (<module 'cloudinit.config.cc_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.
Bug report
_maybe_set_hostname()incloudinit/cmd/main.pycallsutil.get_hostname_fqdn(init.cfg, cloud, metadata_only=True)before entering its onlytry/exceptblock (that block guards just the latercc_set_hostname.handle(...)call).get_hostname_fqdn()incloudinit/util.pythen doesif "hostname" in cfg and cfg["hostname"].find(".") > 0:with no type check orstr()cast oncfg["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 raisesAttributeError: 'int' object has no attribute 'find'— and because the call happens outside the guarded block, the exception propagates uncaught out ofmain_init, killing the entireinit-localstage.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, andcloud-final.serviceon 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
Set a purely-numeric string as the hostname in
user-data:Boot with this cloud-config via the NoCloud datasource (
dsmode: local).Inspect
/var/log/cloud-init.log—init-localfails with the traceback below, andcloud-init status --longreports failure for all stages.Reproduced specifically with Raspberry Pi Imager's cloud-init-based headless setup (
user-data+meta-data+network-configseeded viafile:///boot/firmware), but the crash is in genericcloudinit/util.pyandcloudinit/cmd/main.pycode, not anything Raspberry Pi OS-specific — it should reproduce identically on any NoCloud (or other datasource) boot where a numeric hostname reachesget_hostname_fqdn().Environment details
dsmode: local, seeded fromfile:///boot/firmware)cloud-init logs
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_hostnameundermodules.py), where it is caught and logged only as aWARNINGrather than aborting the stage:Suggested fix: either
str(cfg["hostname"]).find(".")(and equivalent casts elsewhere inget_hostname_fqdn) incloudinit/util.py, or move theutil.get_hostname_fqdn(...)call in_maybe_set_hostnameinside the existingtry/exceptblock so it fails as gracefully as thecc_set_hostname.handle(...)call right below it.