#70252·salt

[Bug]: SyncClientMixin.low() masks all early failures with UnboundLocalError: proc_fn

Author: xescabCreated Sep 9, 2026Updated Sep 9, 2026
Labelsbugneeds-triage

What happened?

In salt/client/mixins.py::SyncClientMixin.low(), proc_fn is assigned at line 381, but the finally block at line 415 unconditionally references it at line 418:

Anything raising between lines 339 and 380 is correctly captured by the broad except at 404 — and then discarded, because the finally raises UnboundLocalError on its way out. Affected call sites include verify_fun() (line 340), the func_globals injection loop, salt.utils.args.format_call(), and jid_event.fire_event(data, "new").

Two consequences:

The real exception is never logged or returned. Callers see only UnboundLocalError: cannot access local variable 'proc_fn' where it is not associated with a value, which points at cleanup code unrelated to the actual fault. Because the finally raises, execution never reaches the store_job() call or namespaced_event.fire_event(data, "ret") that follow it, so the failure is absent from the job cache and the event bus too. Note that a permissions failure on the proc file itself does not trigger this — proc_fn is already bound by the time fopen() runs at line 382. The UnboundLocalError is always a symptom of an earlier, hidden fault, which makes it actively misleading to diagnose.

Any master. Reproducible with a plain RunnerClient; no special configuration required.

Steps to reproduce

import salt.config import salt.runner

opts = salt.config.master_config("/etc/salt/master") client = salt.runner.RunnerClient(opts) client.low("nonexistent.function", {"fun": "nonexistent.function"})

The control flow in isolation:

import os

def low(fail_early): try: if fail_early: raise RuntimeError("the real error") proc_fn = os.path.join("/tmp", "proc", "jid") open(proc_fn, "w+b") except (Exception, SystemExit) as ex: print("broad except captured:", ex) # real error captured here... finally: try: os.remove(proc_fn) # ...then destroyed here except OSError: pass

low(True)

broad except captured: the real error

UnboundLocalError: local variable 'proc_fn' referenced before assignment

Expected behavior

verify_fun() raises CommandExecutionError: 'nonexistent.function' is not available., and low() returns it in data["return"] as the broad except intends.

Actual behavior

UnboundLocalError: cannot access local variable 'proc_fn' where it is not associated with a value

Suggested fix

         try:
  •            proc_fn = None
               self_functions = copy.copy(self.functions)
               salt.utils.lazy.verify_fun(self_functions, fun)

@@ finally: # Job has finished or issue found, so let's clean up after ourselves

  •            try:
  •                os.remove(proc_fn)
  •            except OSError as err:
  •                log.debug("Error attempting to remove master job tracker: %s", err)
  •            if proc_fn is not None:
  •                try:
  •                    os.remove(proc_fn)
  •                except OSError as err:
  •                    log.debug("Error attempting to remove master job tracker: %s", err)

Type of salt install

Official pkg

Major version

3008.x

What supported OS are you seeing the problem on? Can select multiple. (If bug appears on an unsupported OS, please open a GitHub Discussion instead)

ubuntu-22.04

salt --versions-report output

bash
Salt Version:
            Salt: 3008.2

Python Version:
          Python: 3.14.6 (main, Jun 11 2026, 02:19:05) [GCC 11.2.0]

Dependency Versions:
            cffi: 2.0.0
        cherrypy: 18.10.0
    cryptography: 48.0.0
        dateutil: 2.9.0.post0
       docker-py: Not Installed
           gitdb: 4.0.12
       gitpython: 3.1.50
          Jinja2: 3.1.6
         libgit2: Not Installed
    looseversion: 1.3.0
        M2Crypto: Not Installed
            Mako: Not Installed
         msgpack: 1.1.2
    msgpack-pure: Not Installed
    mysql-python: Not Installed
       packaging: 24.0
       pycparser: 3.00
        pycrypto: 3.23.0
    pycryptodome: 3.23.0
          pygit2: Not Installed
    python-gnupg: 0.5.6
          PyYAML: 6.0.3
           PyZMQ: 27.1.0
          relenv: 0.22.14
           smmap: 5.0.2
         timelib: 0.3.0
         Tornado: 6.5.7
             ZMQ: 4.3.5

Salt Extensions:
 saltext.azurerm: 4.4.1

Salt Package Information:
    Package Type: onedir

System Versions:
            dist: ubuntu 22.04.5 jammy
          locale: utf-8
         machine: x86_64
         release: 6.8.0-1053-aws
          system: Linux
         version: Ubuntu 22.04.5 jammy