Skip to content

Python stops trying to create a .pyc if unable to completely write a .pyc file in one go #141930

Description

@stefanor

Bug report

Bug description:

#126606 fixed a bug, in that writing incomplete .pyc files is not going to end well for the system.
But the solution was just to crash the file write, not attempt any retries.

It's not completely unexpected to receive a signal or some other interrupt that results in write() not writing all the provided data. This can be handled.

We've observed incomplete .pyc files in the past in Debian systems, and I just ran into this in a CI job:

https://people.debian.org/~stefanor/upstream/debusine-server_0.13.1.log

  Setting up python3-debusine-server (0.13.1) ...
  os.write() didn't write the full pyc filedpkg: error processing package python3-debusine-server (--configure):
   installed python3-debusine-server package post-installation script subprocess returned error exit status 1

CPython versions tested on:

CPython main branch

Operating systems tested on:

Linux

Linked PRs

Activity

  1. added a commit that references this issue on Nov 25, 2025
  2. cmaloney commented on Nov 25, 2025

    @cmaloney
    Contributor

    EINTR in specific should already be retried when possible (see: PEP-475 and _Py_write which does the underlying I/O).

    If this needs a full well-tested retry loop I'd strongly prefer moving this to use BufferedIO rather than FileIO directly. Yes, it has slightly more overheads but re-implementing "handle all buffering and retry cases" here doesn't seem worth the complexity.

  3. stefanor commented on Nov 25, 2025

    @stefanor
    ContributorAuthor

    Agreed that writing another retry loop is nasty.

    I had missed that retry bit in _Py_write (and misled by the outdated comments that #129011 aims to fix). If it's not EINTR, I wonder why this case was failing... We'll probably find out in time if we implement something better, because the real error will bubble up, rather than the generic os.write() didn't write the full pyc file that masks the error.

  4. cmaloney commented on Nov 25, 2025

    @cmaloney
    Contributor

    Is the process running out of quota/space? It looks like the host is using a new systemd and in that there's a recent change to do quotas on tmp space. My thought here is gh-126606 the underlying cause of the partial write was a file size limit imposed by ulimit so maybe similar.

  5. stefanor commented on Nov 25, 2025

    @stefanor
    ContributorAuthor

    Writing pycache shouldn't go to /tmp, but I'm going to check with the admin of that service if they saw anything.

    Munin graphs for the machine that ran the task don't show any disk issues at that time.

  6. stefanor commented on Nov 25, 2025

    @stefanor
    ContributorAuthor

    Note that EINTR only applies when 0 bytes were written, if the kernel is interrupted after writing some bytes, it may just return the number of bytes written. signal(7) says a local disk is not a "slow" device that could exhibit this behaviour... but I/O stacks are complex, and this is obviously a massive simplification.

  7. stefanor commented on Nov 25, 2025

    @stefanor
    ContributorAuthor

    I'm going to check with the admin of that service if they saw anything.

    They found another instance of this in the log pile: https://piuparts.debian.org/oldstable22testing/fail/tsung_None.log

    Filesystem in question is tmpfs. The admin doesn't think ENOSPC is likely (or they'd see it more often), but I don't think we can rule it out.

    Just getting Python to print the errno error here would be a win for debugging these problems :)

  8. changed the title [-]Python my abort if unable to completely write a .pyc file in one go[/-] [+]Python may abort if unable to completely write a .pyc file in one go[/+] on Nov 25, 2025
  9. brettcannon commented on Nov 25, 2025

    @brettcannon
    Member

    Is this that important to succeed at the write in the end? .pyc files are an optimization, so if they don't end up being written then it shouldn't matter that much. Plus the incomplete file should be deleted, so there's shouldn't be any trash left over.

  10. stefanor commented on Nov 25, 2025

    @stefanor
    ContributorAuthor

    Yeah, at least the write is atomic, so we shouldn't be left with broken .pyc files, as we were in the past. (I used to see numerous bug reports from broken systems due to corrupt .pyc files).

    If the intention is that failing to write .pyc files is OK, then maybe py_compile should raise a warning and exit 0, when one of these is hit?

  11. added a commit that references this issue on Nov 25, 2025
  12. cmaloney commented on Nov 25, 2025

    @cmaloney
    Contributor

    re: Is not writing a .pyc actually a failure?

    I think that depends a lot on use case / context. In packaging sometimes the .pyc are intentionally included (archlinux), sometimes generated on install (debian), sometimes excluded (ex. wheel). Installing wheels depends on where (pypa/installer).

    re: Atomic, what makes the .pyc writing atomic is the_os.replace(path_tmp, path) in this code I think; multiple write calls means a partially written file exists (even if only briefly) which in theory another process could pick up.

    👍 for a minimal including errno in the exception (raise OSError("os.write() didn't write the full pyc file") line).

  13. vstinner commented on Nov 26, 2025

    @vstinner
    Member

    Python may abort if unable to completely write a .pyc file in one go

    I don't think that the title is correct. Python doesn't abort, but only raises an OSError which can be catched.

  14. changed the title [-]Python may abort if unable to completely write a .pyc file in one go[/-] [+]Python raise an `OSError` if unable to completely write a .pyc file in one go[/+] on Nov 26, 2025
  15. brettcannon commented on Nov 26, 2025

    @brettcannon
    Member

    re: Is not writing a .pyc actually a failure?

    I think that depends a lot on use case / context.

    Since we are talking about patching CPython I would argue it's our context and in that instance it isn't a failure.

  16. changed the title [-]Python raise an `OSError` if unable to completely write a .pyc file in one go[/-] [+]Python stops trying to create a `.pyc` if unable to completely write a `.pyc` file in one go[/+] on Nov 26, 2025
  17. stefanor commented on Nov 26, 2025

    @stefanor
    ContributorAuthor

    @brettcannon: I described it as an abort, because it causes pycompile to abort. You're correct, of course, that it's not an abort in the usual automatic .pyc generation case.

  18. gpshead commented on Nov 27, 2025

    @gpshead
    Member

    That pycompile aborted is a good thing. Something was wrong the system and it couldn't do its job. PR set to auto-merge with backports through 3.13. Thanks for just making that use the normal io stack. Much simpler and problematic systems will now see the actual underlying error when appropriate. Odd that FileIO was used directly there before.

  19. added a commit that references this issue on Nov 27, 2025
  20. added a commit that references this issue on Nov 27, 2025
  21. added a commit that references this issue on Dec 1, 2025
  22. added a commit that references this issue on Dec 1, 2025
  23. added a commit that references this issue on Dec 6, 2025
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/ directorytopic-IOtopic-importlibtype-bugAn unexpected behavior, bug, or error

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions