Skip to content

Logger error under Pythonw results in a crash and recursion error #107792

Closed as not planned

Description

@ElliotGarbus

Bug report

Running under pythonw, log messages to stderr cause a crash with recursion.

The error messages:

Traceback (most recent call last):
  File "logging\__init__.py", line 1113, in emit
AttributeError: 'NoneType' object has no attribute 'write'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "logging\__init__.py", line 1113, in emit
AttributeError: 'NoneType' object has no attribute 'write'

During handling of the above exception, another exception occurred:
...
During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "kivy\logger.py", line 310, in emit
  File "kivy\logger.py", line 284, in _configure
  File "logging\__init__.py", line 1489, in info
  File "logging\__init__.py", line 1634, in _log
  File "logging\__init__.py", line 1644, in handle
  File "logging\__init__.py", line 1706, in callHandlers
  File "logging\__init__.py", line 978, in handle
  File "logging\__init__.py", line 1118, in emit
  File "logging\__init__.py", line 1031, in handleError
  File "kivy\logger.py", line 390, in write
  File "logging\__init__.py", line 1501, in warning
  File "logging\__init__.py", line 1634, in _log
  File "logging\__init__.py", line 1644, in handle
  File "logging\__init__.py", line 1706, in callHandlers
  File "logging\__init__.py", line 978, in handle
  File "logging\__init__.py", line 1118, in emit
  File "logging\__init__.py", line 1031, in handleError
  File "kivy\logger.py", line 390, in write
  File "logging\__init__.py", line 1501, in warning
  File "logging\__init__.py", line 1634, in _log
  File "logging\__init__.py", line 1644, in handle
  File "logging\__init__.py", line 1706, in callHandlers
  File "logging\__init__.py", line 978, in handle
  File "logging\__init__.py", line 1118, in emit
  File "logging\__init__.py", line 1031, in handleError
...
RecursionError: maximum recursion depth exceeded
...

Checklist

  • I am confident this is a bug in CPython, not a bug in a third-party project
  • I have searched the CPython issue tracker, and am confident this bug has not been reported before

A clear and concise description of the bug

In pythonw, stderr is None. This triggers a problem in the exception handling of the emit code in the logger.

def emit(self, record):

# The emit code in the standard library:

  def emit(self, record):
      """
      Emit a record.

      If a formatter is specified, it is used to format the record.
      The record is then written to the stream with a trailing newline.  If
      exception information is present, it is formatted using
      traceback.print_exception and appended to the stream.  If the stream
      has an 'encoding' attribute, it is used to determine how to do the
      output to the stream.
      """
      try:
          msg = self.format(record)
          stream = self.stream
          # issue 35046: merged two stream.writes into one.
          stream.write(msg + self.terminator)
          self.flush()
      except RecursionError:  # See issue 36272
          raise
      except Exception:
          self.handleError(record)

I believe the more correct solution is to handle the Attribute exception caused when sys.stderr is None.

    def emit(self, record):
        """
        Emit a record.

        If a formatter is specified, it is used to format the record.
        The record is then written to the stream with a trailing newline.  If
        exception information is present, it is formatted using
        traceback.print_exception and appended to the stream.  If the stream
        has an 'encoding' attribute, it is used to determine how to do the
        output to the stream.
        """
        try:
            msg = self.format(record)
            stream = self.stream
            # issue 35046: merged two stream.writes into one.
            stream.write(msg + self.terminator)
            self.flush()
        except AttributeError:  # handle the Attribute error, return, ignoring the request.
            return # this would cover the case for pythonw or whenever sys.stderr is None
        except RecursionError:  # See issue 36272
            raise
        except Exception:
            self.handleError(record)

I would submit a PR - but I'm not confident I understand the logger with enough depth to not open up other issues. There appears to be a number of issues that are related that this fix would address.

Activity

  1. sunmy2019 commented on Aug 10, 2023

    @sunmy2019
    Member
            except AttributeError:  # handle the Attribute error, return, ignoring the request.
                return # this would cover the case for pythonw or whenever sys.stderr is None

    This is too wildcarded. How about something like

                msg = self.format(record)
                stream = self.stream
                # issue 35046: merged two stream.writes into one.
                if stream is not None:
                    stream.write(msg + self.terminator)
                self.flush()
  2. ElliotGarbus commented on Aug 10, 2023

    @ElliotGarbus
    Author

    I managed to fix my issue by not adding the console handler to the logger when sys.stderr is None.
    @sunmy2019 Your solution looks good to me.
    I can close this issue or leave it open it is worth taking a closer look.

  3. sunmy2019 commented on Aug 10, 2023

    @sunmy2019
    Member

    I see. I think it can be left open. We can add checks here.

    def __init__(self, stream=None):
    """
    Initialize the handler.
    If stream is not specified, sys.stderr is used.
    """
    Handler.__init__(self)
    if stream is None:
    stream = sys.stderr
    self.stream = stream

    At least we can prevent emit itself from causing the recursion.

  4. ElliotGarbus commented on Aug 10, 2023

    @ElliotGarbus
    Author

    Good idea.

  5. added
    stdlibStandard Library Python modules in the Lib/ directory
    on Nov 26, 2023
  6. vsajip commented on Jan 30, 2024

    @vsajip
    Member

    I think the solution used by @ElliotGarbus - to not add the console handler when running in pythonw - makes the most sense for the use case. I'm not against putting a check for a None value just before self.stream = stream - but there would also need to be a check in setStream(), and perhaps the check should be for hasattr(stream, 'write') rather than a simple check for None. Since this is a change in behavior (e.g. an exception will be raised by the check where one wasn't raised before) it seems like such a change would have to be not backported.

  7. serhiy-storchaka commented on Jul 22, 2026

    @serhiy-storchaka
    Member

    Nothing to do on our side. The error is produced by third-party handler. Closed as not planned.

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

    stdlibStandard Library Python modules in the Lib/ directorytype-bugAn unexpected behavior, bug, or error

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions