njs blog

Why I'm not collaborating with Kenneth Reitz

[Content Warning: parts of this post could be triggering for those who have experienced gaslighting or other forms of abuse]

Kenneth Reitz is a famous Python developer, best-known for founding the Requests project. Until a few years ago, I'd never interacted with him in any serious way, but I thought highly of him.

I appreciated (and still appreciate) his design taste, and emphasis on usability and beauty. Requests is a piece of critical infrastructure that holds up large parts of the software world; his puckish insistence that it's actually an "art project" appealed to my anarchist sympathies. I admired (and still admire) his openness with his mental health struggles. When I was starting my project Trio, I wanted to emphasize its friendliness and accessibility, so I borrowed his "for humans" tagline, and started the documentation by quoting him.

Then I started working on adding async support to requests.

A timeline of async in Requests, and the Requests 3 fundraiser

In August 2017, I started working on adding async support to urllib3, which is the underlying HTTP library that Requests uses. This was highly experimental. Historically, the state of the art was that you had one HTTP client library for synchronous code, one for Twisted, one for Tornado, one for asyncio, and so on – each maintained as independent projects that didn't share code. Everyone knows this is silly, but it's very challenging to fix: you need deep expertise in HTTP, and in all these different approaches to networking, and some clever idea for how to reconcile their seemingly irreconcilable APIs. So every previous attempt had failed. Now I thought I had a clever idea, so I gave it a try.

Reitz was very interested in this work, because he very much wanted async support in Requests, but – as he told me – didn't know how to solve these problems himself. We had some video calls and IRC discussions, and he tried to leverage his notoriety to recruit volunteers and send them my way. Nothing much came of this, but I kept plugging away, along with some other Trio contributors.

Screenshot of Reitz's fundraising page, showing the promised features in Requests 3

Then on March 7 2018, he announced that work had begun on "Requests 3", that its headline feature would be the native async/await support I was working on, and that he was seeking donations to make this happen.

Most open-source projects struggle to raise a few thousand dollars to hold a meeting, but this got people excited. He was deluged with donations from both individuals and large companies like Microsoft, Google, Slack, etc., and the fundraiser total quickly reached ~$30k.

On March 15 2018, he contacted me to talk about the fundraiser. He told me he was uncertain what to do with this amount of money – he said his original goal was just to raise $5k to buy a computer. Privately, I was skeptical that the $5k computer had anything to do with Requests. Requests is a small pure-Python library; if you want to work on it, then any cheap laptop is more than sufficient. $5k is the price of a beefy server or top-end gaming rig. But I figured that even if he spent $5k of the money on some unrelated computer, we could call that compensation for his past work, and it would still leave ~$25k to fulfill the promises he'd made in the fundraiser. And this was clearly a great opportunity to build some amazing new stuff. So I didn't say anything about the computer.

Instead, I gave some general tips from my experience with fund-raising and grants, emphasizing the importance of transparency to maintain trust, and recommending he set up a fiscal sponsorship relationship with the Python Software Foundation (PSF) or a similar non-profit. And I tried to help with finding ways to spend the money effectively – for example, I was already working full-time, but I contacted one of the volunteers who'd been helping me to see if they were available for a contracting gig.

Around this time, he also did some experiments with our work-in-progress on urllib3, which led to a tweet demonstrating "Requests Core" issuing multiple HTTP requests in parallel. "Requests Core" here was a snapshot of our work, that he forked and renamed. As far as I know, the only thing added was some basic HTTP/2 support, but unfortunately (and despite our warnings beforehand) this used a dead-end approach, so the code wasn't useful.

Up to this point, there were definitely some odd features in our interactions, but, you know, people are odd sometimes. I personally wouldn't have announced a fundraiser without first talking to the people actually working on the features I was promising, but I was confident we could find some way to spend the money effectively. Maybe his HTTP/2 code wasn't useful, but at least he was getting some experience with async/await. I thought it would work out OK.

Over the next few months, there were some more odd things – different members of the Requests maintainers team reported hearing very different stories about what was happening to the money. But the big change came in late May 2018, when I left UC Berkeley and started consulting. This seemed like a potential win-win – I was looking for work and excited about the project, and he was stuck with money he had no way to spend. So I sent him an email to explore further.

After a month and several follow-up pings, he finally responded. His main points were:

  • He actually only raised $28k.
  • "Most of it" went to taxes.
  • He expected me to do the work of fulfilling the commitments he'd made for new features in Requests 3.
  • But none of the money was available to fulfill those commitments; instead, he was going to wait for me to implement the new features for him, and then he needed the entire $28k to pay for writing documentation for my features.
  • If I couldn't fulfill his commitments on a volunteer basis, he encouraged me to hold my own fundraiser.

He ended by suggesting we do a call that week to discuss details.

I was bewildered. That's not how taxes work. It's not how commitments work. The idea that novel technology stacks are free but a few pages of docs cost $28k is bizarre. The idea that you can't afford to implement new features because you're going to spend the money on documenting the new features you can't afford to build... it doesn't make any sense at all.

If he'd found another way to use the money on Requests, then I would have been totally happy. I didn't have any claim on the money. But this was something else entirely. I was extremely concerned. But I still wanted to get the best outcome we could for the project and the community, so I tried to keep the lines of communication open. I agreed that a call would be a good idea, and suggested some times. I also expressed my worry that he was risking his reputation – more strongly this time – and reiterated my offer to help, writing: "I think right now there is a real risk that requests 3 never materializes and the public impression becomes "oh yeah Kenneth Reitz stole that money". I really hope neither of these things happens. But hope isn't a plan. I think we need a plan."

At this point he stopped answering my emails, and deleted the fundraising page – the one with the record of donations received, and what he was promising in return – from his website (before / after). He also updated the Requests documentation and his blog (before / after) to remove references to the deleted page. Some months later, he put up a new page at the original URL, requesting that anyone who had questions about the fundraiser should contact him privately.

Our only contact since then was an email he sent me out of the blue on February 9 this year. Instead of responding to anything I'd said before, he suggested that he and I write a joint grant proposal to the PSF, to pay me to do the same work that his fundraiser was allegedly funding. Of course this was a non-starter. I'm pretty sure the PSF is too savvy to fund something like this without asking some tough questions about where the other money went. And even if they didn't, and even if we somehow ignored the ethical issues, he was effectively asking me to link our reputations together, so that if his handling of the fundraiser blew up, it would implicate me as well. I didn't reply.

Was it an honest mistake?

Not everyone is familiar with standard practices for handling fundraising in open-source projects. So as a comparison, let me explain how the Python Software Foundation's Packaging Working Group handled the funding for the new PyPI.

Since this was our first time getting an external grant like this, we started by making a plan for what to do and who would do it, including identifying existing contributors who were available to work as contractors. Only after that was in place did we apply for the money.

Then after the money arrived, we didn't just hand it over. Each of the contractors wrote up a few paragraphs to formally state their rates and what they were committing to, the group reviewed them, and then we held a quick vote over email to approve them. The contractors who were members of the Working Group didn't vote on their own proposals. Everyone provided regular invoices. And the whole process was ultimately overseen by the PSF's Board of Directors, who are elected by the community.

This is a pretty lightweight process, and it isn't infallible, but it provides a baseline level of transparency and accountability. And the PSF is happy to provide this service for any Python-related project; for example, they handle donations for Flask and related projects.

Perhaps Reitz simply didn't know how these things are normally done, and this is all an unfortunate but understandable mistake. However, I find this unlikely. At the time Reitz ran his fundraiser, he was sitting on the PSF Board of Directors. And as a member of the Packaging Working Group, he participated in the voting for the PyPI funding, which happened a few months before he started his fundraiser. And yet, none of the PSF staff I've talked to knew about his fundraiser until I told them about it.

In short: He chose a fundraiser structure that avoids standard accountability mechanisms he was familiar with. He never had any plan or capability to deliver what he promised. And when I offered a way for him to do it anyway, he gave me some bafflegab about how expensive it is to write docs. Effectively, his public promises about how he would use the Requests 3 money were lies from start to finish, and he hasn't shown any remorse or even understanding that this is a problem.

A betrayal of trust like this damages the entire community. It's hard enough raising money for open-source as it is; this kind of thing really doesn't help.

And on a more personal level, I felt his interactions with me were extremely manipulative. I felt like he tried to exploit me, and that he tried to make me complicit in covering up his lies to protect his reputation. I was extremely uncomfortable with the idea of going along with this, but he created a situation where my only other options were to either give up on working on async entirely, or else to go public with the whole story, at potentially serious cost to myself.

Was this a one-off mistake, or part of a larger pattern?

I wasn't sure what to do, so I started quietly contacting other community members to get more context. I quickly discovered that contrary to Reitz's public reputation, every time I talked to anyone who had worked with him directly, they expressed serious discomfort with him, and many had their own disturbing stories – mine was nowhere near the worst. For example, Ian Stapleton Cordasco volunteered to go on the record publicly, stating: "Having to deal with Kenneth all these years has made it such that I barely work on python open source software anymore and have largely, quietly left the community".

Something I found especially disturbing: whenever I talked to any of his long-term collaborators about my experience, they immediately jumped to reassure me that I wasn't going crazy. Which... I mean, I appreciated the support. But it was clear this isn't the first time they'd had to do this. Apparently after people start working with Reitz, they always need to be reassured that they can trust their own perceptions. These collaborators have been doing this for so long that this seems normal to them. But it's not normal.

This is the classic "missing stair" problem. Those in the inner circle quietly work around the toxic person. Outsiders come in blind. I'm pretty well-connected in the Python world, and I came in blind. In retrospect, I can see some warning signs. The insistence on auteur status now seems less like a charming quirk, and more like a calculated bluff to claim credit and power while denying responsibility. An insistence on "positivity" is a common tactic among those who want to avoid accountability. But they fooled me.

Something I keep thinking about: the first time I talked to him about async in Requests, months before the fundraiser, he made a strange comment: he pointed out that he was totally dependent on me to implement this, and therefore, if I were to demand that he make Requests use Trio (my library) by default instead of AsyncIO (the better-known competitor), then he'd have no choice but to acquiesce. It struck me as an incredibly strange thing to bring up – it was almost like he was asking me to manipulate him. At the time, I mumbled something about wanting to succeed on the merits, not by blackmail, and recommended that he not set a default at all. In retrospect, I'm reminded of how con artists often start by tempting their victims into some minor unethical act, so that as the con escalates they feel trapped.

His collaborators also consistently cited his bipolar disorder as an excuse for whatever he did. I think this is deeply unfair to Reitz, and to everyone struggling with mental health issues. Illness does not erase the harm someone does to others, or their responsibility for their actions. Many people manage their conditions without causing this kind of harm, and when they mess up, they make amends, just like the rest of us. If someone can't do that, then as a community, we can have compassion but shouldn't give them power and influence.

I think a lot of people don't realize how little Reitz actually has to do with Requests development. For many years now, actual maintenance has been done almost exclusively by other volunteers. If you look at the maintainers list on PyPI, you'll see he doesn't have PyPI rights to his own project, because he kept breaking stuff, so the real maintainers insisted on revoking his access. If you clone the Requests git repo, you can run git log requests/ to see a list of every time someone changed the library's source code, either directly or by merging someone else's pull request. The last time Reitz did either was in May 2017, when he made some whitespace cleanups.

At least as far as commits go, his main contributions since then appear to consist of merging some small doc fixes, and monetizing the project by adding donation links, ads, intrusive sponsored links, etc. All of this money goes directly into his pocket, not the project's maintainers.

I also learned that he has a history of selling premium support contracts for Requests, where he took the money and then delegated the actual work to unpaid volunteers.

I don't have any objection to trying to make money from open-source. I've written before about how open-source doesn't get nearly enough investment. I do object to exploiting volunteers, driving out community members, and lying to funders and the broader community. Reitz has a consistent history of doing all these things.

Why am I writing this?

I've struggled to decide what to do here. Since last year, I've tried to be very cautious when speaking to people about this, because I don't want to start false rumors or feed an internet mob. (This has also meant keeping quiet about the work we've been doing on async in urllib3, and made it difficult for me to work on it at all.) And I'm scared of how making this public might affect my own reputation and mental health.

Ultimately, I decided to speak out because I care deeply about the Python community and its members. If one of our community's most prominent members freely lies to donors and harms volunteers, and if we all let that go without saying anything, then that puts everything we've built together at risk. And I'm in a better position than many to speak up.

So what happens now?

Since this is the internet, I have to say explicitly: Please do not harass or abuse Reitz. That's never appropriate. (And in case you're the kind of person that doesn't find moral arguments convincing, then consider: he clearly wants attention.)

I call on Reitz to make a public accounting of the money he raised and how it was spent.

I urge the Requests project maintainers to transition their project to a more normal, less dysfunctional governance model. You can acknowledge his contributions without buying into his personal mythology. His insights are not irreplaceable. You know this situation is harming you and your users. You and your users are more important than his ego.

Beyond that, I'm going to focus on my own work. I'm done keeping secrets to protect Reitz from the consequences of his actions; what happens next is up to him and the larger Python community.

If anyone needs a listening ear, I can be reached at njs@pobox.com. I'm also around at PyCon this weekend.

Edit history

  • 2019-05-04: Initial post.
  • 2019-05-06: The original post quoted several anonymous community members, with the goal of further illustrating the climate created by Reitz's behavior. I received feedback that the anonymous quotes weren't adding to constructive discussion. On consideration, I agree, so I removed them. I kept all the text describing things I experienced personally, as well as the one credited quote.

Previous: Beautiful tracebacks in Trio v0.7.0