Skip to content

[Bug] BaseNeuron startup writes 'full path:' to stdout via bare print(), bypassing bt.logging and polluting non-TTY consumers #1012

@ebios-star

Description

@ebios-star

Description

gittensor/utils/config.py:39 — inside check_config(...), which runs on every miner/validator boot via BaseNeuron.__init__ → self.check_config(self.config) — there is a bare print() that writes the resolved neuron path directly to stdout:

def check_config(cls, config: Any):
    r"""Checks/validates the config namespace object."""
    bt.logging.check_config(config)

    full_path = os.path.expanduser(
        '{}/{}/{}/netuid{}/{}'.format(
            config.logging.logging_dir,
            config.wallet.name,
            config.wallet.hotkey,
            config.netuid,
            config.neuron.name,
        )
    )
    print('full path:', full_path)                       # ← bare print to stdout
    config.neuron.full_path = os.path.expanduser(full_path)
    if not os.path.exists(config.neuron.full_path):
        os.makedirs(config.neuron.full_path, exist_ok=True)

This is the only print() call in gittensor/, neurons/, or tests/ outside CLI/JSON-output paths — verified via grep -rn '^\s*print(' --include='*.py' gittensor/ neurons/. The leading 'full path:' formatting strongly suggests it's leftover from initial development/debugging in the upstream Bittensor template (the file still carries the Yuma Rao / OpenTensor 2023 copyright header) and was never removed.

Why this is a problem

  1. Bypasses bt.logging configuration. Every other startup line goes through bt.logging.{info,debug,warning} — operators control verbosity, format, and destination via --logging.* flags or env. This print() ignores all of that. Setting --logging.debug=False does not silence it; redirecting log output via bittensor's mechanism does not capture it.

  2. Pollutes stdout where it isn't expected. Operators running validators/miners under systemd, docker logs, journalctl, structured-log shippers (Vector, Fluent Bit), or any aggregator that distinguishes stdout from logger output get a stray, unstructured line in the wrong stream — different from the rest of the startup trace, harder to filter.

  3. Distinct from Bug: noise in stdout interfere json parsing #956. That issue is about --json CLI commands writing warnings to stdout and breaking jq. This one is in BaseNeuron's startup path, fires on every miner/validator boot regardless of CLI invocation, and isn't reachable through the CLI --json paths Bug: noise in stdout interfere json parsing #956 covers. They're independent fixes.

Steps to Reproduce

  1. Start any neuron (validator, miner, or any subclass of BaseNeuron):
    $ python neurons/validator.py --wallet.name foo --wallet.hotkey bar --netuid 74 2>/dev/null
    full path: /home/user/.bittensor/miners/foo/bar/netuid74/validator
    ...
    
  2. The 2>/dev/null redirect drops bt.logging output (it goes to stderr by default), but the 'full path: ...' line still appears — proving it's on stdout, not the logger stream.
  3. Conversely, python neurons/validator.py ... 1>/dev/null suppresses 'full path:' while leaving the bt.logging trace intact — confirming the same.

Expected Behavior

Either:

  • Route through the existing logger: bt.logging.debug(f'Neuron full_path: {full_path}') — keeps the diagnostic for anyone who wants it (--logging.debug), respects the operator's logging configuration, and goes to the same stream as the rest of startup output.
  • Or just drop the line — full_path is already used in the immediately following os.makedirs(...) call, and the value is recoverable from config.neuron.full_path post-init for any operator who wants to inspect it.

Suggested Fix

Single-line change:

-    print('full path:', full_path)
+    bt.logging.debug(f'Neuron full_path: {full_path}')
     config.neuron.full_path = os.path.expanduser(full_path)

(The bt.logging.debug form is already imported in the file at line 23.)

If you'd rather just remove it, that's also a one-line change and avoids the (tiny) extra debug noise.

Scope

Affects only the one print() call. No behaviour change for the path construction itself — config.neuron.full_path and the os.makedirs(...) call on the next two lines are untouched.

Environment

  • Affected file: gittensor/utils/config.py:39
  • Branch: test
  • Reproducible on every neuron boot since the file was inherited from the upstream Bittensor template (commit a85691c "thus spoke zarathustra", per git log -L 39,39:gittensor/utils/config.py).

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions