Skip to content

Meshtastic CLI Disconnect Read Failure #855

Closed

Description

@radioboyQ

Hardware: tbeam
Firmware: 2.6.11.60ec05e
Meshtastic CLI Version: 2.7.4

After successfully running a command using the CLI, the Serial Stream doesn't close properly.

Example command and error:

$ meshtastic --info                       
Connected to radio

Owner: joebishop (a8f8)
My info: { "myNodeNum": 240560376, "rebootCount": 3, "minAppVersion": 30200, "pioEnv": "tbeam", "deviceId": "", "firmwareEdition": "VANILLA", "nodedbCount": 0 }
Metadata: { "firmwareVersion": "2.6.11.60ec05e", "deviceStateVersion": 24, "canShutdown": true, "hasWifi": true, "hasBluetooth": true, "positionFlags": 811, "hwModel": "TBEAM", "hasPKC": true, "excludedModules": 1280, "hasEthernet": false, "role": "CLIENT", "hasRemoteHardware": false }

<all node information like normal, snipped for brevity>
Primary channel URL: https://meshtastic.org/e/#CgcSAQE6AggNEgwIATgBQANIAVAaeEA

ERROR file:stream_interface.py __reader line:227 Unexpected exception, terminating meshtastic reader... 'NoneType' object cannot be interpreted as an integer

Some initial troubleshooting shows commands work, but the error is thrown at the end of the session. Regardless of which option is used, (--nodes, --set lora.region US, etc) the error shows up. The command executes successfully against the node, but it appears closing the stream has a failure.

Traceback is shown when using --port /dev/ACM#. Full system path cut for brevity.

WARNING file:stream_interface.py __reader line:216 Meshtastic serial port disconnected, disconnecting... read failed: [Errno 9] Bad file descriptor
Exception in thread stream reader:
Traceback (most recent call last):
  File "/usr/lib/python3.12/threading.py", line 1073, in _bootstrap_inner
    self.run()
  File "/usr/lib/python3.12/threading.py", line 1010, in run
    self._target(*self._args, **self._kwargs)
  File "./meshtastic/.meshtastic/lib/python3.12/site-packages/meshtastic/stream_interface.py", line 232, in __reader
    self._disconnected()
  File "./meshtastic/.meshtastic/lib/python3.12/site-packages/meshtastic/stream_interface.py", line 98, in _disconnected
    self.stream.close()
  File "./meshtastic/.meshtastic/lib/python3.12/site-packages/serial/serialposix.py", line 533, in close
    os.close(self.fd)
OSError: [Errno 9] Bad file descriptor

Thanks for looking into this. I'm happy to provide any additional information or troubleshooting steps.

Activity

  1. ianmcorvidae commented on Nov 9, 2025

    @ianmcorvidae
    Contributor

    @SpudGunMan thinking this could be related to your change. Is there anything you can see here?

  2. SpudGunMan commented on Nov 10, 2025

    @SpudGunMan
    Contributor

    Like issues covered before? Yes the errors have been all along imo, the close was just removing the time wait close close before.. so the issue is out side the scope of the interface close at the end?

  3. SpudGunMan commented on Nov 10, 2025

    @SpudGunMan
    Contributor

    Add a wait/sleep before closing to slow it down for serial?

  4. ogarcia commented on Nov 10, 2025

    @ogarcia

    I have exactly the same problem with a Heltec v3 connected via serial port to /dev/ttyUSB0.

    And I don't know if it's related, but when I change a parameter with --set, I get this other error:

    ERROR file:stream_interface.py __reader line:227 Unexpected exception, terminating meshtastic reader... 'NoneType' object cannot be interpreted as an integer
    
  5. SpudGunMan commented on Nov 10, 2025

    @SpudGunMan
    Contributor

    The command will work it looks like as well? But the error is after set?

  6. ogarcia commented on Nov 10, 2025

    @ogarcia

    The command will work it looks like as well? But the error is after set?

    The command works correctly (it sets and changes the value) but gives an error. This is what it says when fully executed when changing any value:

    % meshtastic -s --set telemetry.device_telemetry_enabled true
    Connected to radio
    Set telemetry.device_telemetry_enabled to true
    Writing modified preferences to device
    Writing telemetry configuration to device
    ERROR file:stream_interface.py __reader line:227 Unexpected exception, terminating meshtastic reader... 'NoneType' object cannot be interpreted as an integer
    

    The same error also occurs if you use --export-config (at the very end):

    .
    .
    .
      telemetry:
        deviceTelemetryEnabled: true
        deviceUpdateInterval: 43200
    owner: Meshtastic
    owner_short: MESH
    ringtone: 24:d=32,o=5,b=565:f6,p,f6,4p,p,f6,p,f6,2p,p,b6,p,b6,p,b6,p,b6,p,b,p,b,p,b,p,b,p,b,p,b,p,b,p,b,1p.,2p.,p
    
    ERROR file:stream_interface.py __reader line:227 Unexpected exception, terminating meshtastic reader... 'NoneType' object cannot be interpreted as an integer
    
  7. SpudGunMan commented on Nov 10, 2025

    @SpudGunMan
    Contributor

    I'm not near a keyboard but was pondering via 🤖 the issue just leaks, question isn't so much the patch but how to find the drip?

    I had these errors prior, it's just cleaning them properly?

    Here’s the direct analysis and a suggested fix for the bug in meshtastic/python issue #855, based on the code at meshtastic/stream_interface.py, specifically in the __reader method and its call to _disconnected.

    🤖Diagnosis:

    • The error ('NoneType' object cannot be interpreted as an integer) and OSError: [Errno 9] Bad file descriptor are triggered during cleanup.
    • In the finally clause of __reader, self._disconnected() is called. That method attempts to self.stream.close() (if not None).
    • The root cause is likely that self.stream is already closed, set to None, or its fd is invalid by the time this code runs—potentially because an exception in serial communication or double cleanup occurs.

    Target fix area:

    • Stream close/shutdown in _disconnected needs to robustly check the stream and its properties before closing, ideally inside a try/except (ignoring already-closed descriptors).

    Patch sketch:

    def _disconnected(self) -> None:
        MeshInterface._disconnected(self)
        logger.debug("Closing our port")
        # Only attempt to close if stream is valid and open
        if self.stream is not None:
            try:
                # Platform-specific: serial.Serial has an 'is_open' attribute
                if hasattr(self.stream, "is_open") and self.stream.is_open:
                    self.stream.close()
            except Exception as e:
                # You might also want to log or specifically suppress errno 9 ('Bad file descriptor')
                logger.debug(f"Exception when closing stream: {e}")
            finally:
                self.stream = None

    This type of change should prevent attempts to close an already-closed stream and gracefully ignore related errors.

  8. ianmcorvidae commented on Nov 10, 2025

    @ianmcorvidae
    Contributor

    It looks like the is_open property doesn't update right away, or something. I couldn't get a version similar to that to work, because it'd claim to be open and then throw the error. For now, I just wrapped it in another try-catch. It's a bit ugly, but I'd rather it try to close it twice than fail to close it, so.

  9. ianmcorvidae commented on Nov 10, 2025

    @ianmcorvidae
    Contributor

    Accordingly, should be fixed in dbc0101

  10. wintermute101 commented on Nov 13, 2025

    @wintermute101

    I installed version commit 0906fc6
    Still have same error:

    Channels:
      Index 0: PRIMARY psk=default { "psk": "AQ==", "moduleSettings": { "positionPrecision": 13, "isMuted": false }, "channelNum": 0, "name": "", "id": 0, "uplinkEnabled": false, "downlinkEnabled": false }
    
    Primary channel URL: https://meshtastic.org/e/#CgcSAQE6AggNEhgIARAGGPoBIAsoBTgDQANIAVAbaAHABgE
    
    ERROR file:stream_interface.py __reader line:230 Unexpected exception, terminating meshtastic reader... 'NoneType' object cannot be interpreted as an integer
    
  11. ianmcorvidae commented on Nov 13, 2025

    @ianmcorvidae
    Contributor

    Hm, okay, that must be another error. I added some additional logging and fixed one error that the tests found in f15a0bd -- if you're able to, would you mind testing again with that commit?

  12. wintermute101 commented on Nov 13, 2025

    @wintermute101

    Here you go:

    Primary channel URL: https://meshtastic.org/e/#CgcSAQE6AggNEhgIARAGGPoBIAsoBTgDQANIAVAbaAHABgE
    
    ERROR file:stream_interface.py __reader line:231 Unexpected exception, terminating meshtastic reader... 'NoneType' object cannot be interpreted as an integer
    Traceback (most recent call last):
      File "/home/wintermute/Projects_root/meshtastic/lib/python3.12/site-packages/meshtastic/stream_interface.py", line 169, in __reader
        b: Optional[bytes] = self._readBytes(1)
                             ^^^^^^^^^^^^^^^^^^
      File "/home/wintermute/Projects_root/meshtastic/lib/python3.12/site-packages/meshtastic/stream_interface.py", line 120, in _readBytes
        return self.stream.read(length)
               ^^^^^^^^^^^^^^^^^^^^^^^^
      File "/home/wintermute/Projects_root/meshtastic/lib/python3.12/site-packages/serial/serialposix.py", line 575, in read
        buf = os.read(self.fd, size - len(read))
              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    TypeError: 'NoneType' object cannot be interpreted as an integer
    
  13. ianmcorvidae commented on Nov 13, 2025

    @ianmcorvidae
    Contributor

    Yeah, I see that the CI version of the tests failed as well. I'm reverting a bunch of stuff to get this back to how it was before.

  14. ianmcorvidae commented on Nov 13, 2025

    @ianmcorvidae
    Contributor

    Reverted all of the stuff refactoring how close and such work in 1088cc6

  15. wintermute101 commented on Nov 13, 2025

    @wintermute101

    Info now works fine! :)

    Primary channel URL: https://meshtastic.org/e/#CgcSAQE6AggNEhgIARAGGPoBIAsoBTgDQANIAVAbaAHABgE

    no errors

    there is some issue with reboot (on rpi pico - when reboot port goes out) but it is not related to this issue.

    ../bin/meshtastic  --port /dev/ttyACM0 --reboot
    Connected to radio
    INFO file:node.py reboot line:608 Telling node to reboot in 10 seconds
    WARNING file:stream_interface.py __reader line:216 Meshtastic serial port disconnected, disconnecting... device reports readiness to read but returned no data (device disconnected or multiple access on port?)
    
  16. SpudGunMan commented on Nov 13, 2025

    @SpudGunMan
    Contributor

    My original hunt was to find why I was seeing it so much in api runtime

    I wonder if the original idea needed a wait or a none check to avoid the extra errors.

    Sorry for the problems

  17. SpudGunMan commented on Nov 13, 2025

    @SpudGunMan
    Contributor

    One random thing I did notice either related to this or firmware patches.

    Disconnect reconnect was or is working better under current release's

  18. SpudGunMan commented on Nov 13, 2025

    @SpudGunMan
    Contributor

    I also wonder if the work JB was tracking on WiFi issues and platform are in anyway related?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions