惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

C
Cisco Blogs
Cyberwarzone
Cyberwarzone
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
SecWiki News
SecWiki News
Martin Fowler
Martin Fowler
T
Tor Project blog
N
Netflix TechBlog - Medium
C
Cybersecurity and Infrastructure Security Agency CISA
V
Vulnerabilities – Threatpost
V
Visual Studio Blog
GbyAI
GbyAI
PCI Perspectives
PCI Perspectives
D
DataBreaches.Net
Jina AI
Jina AI
H
Heimdal Security Blog
云风的 BLOG
云风的 BLOG
P
Privacy International News Feed
A
About on SuperTechFans
J
Java Code Geeks
美团技术团队
H
Hackread – Cybersecurity News, Data Breaches, AI and More
N
News | PayPal Newsroom
有赞技术团队
有赞技术团队
MyScale Blog
MyScale Blog
博客园 - 司徒正美
C
Check Point Blog
T
Threat Research - Cisco Blogs
Attack and Defense Labs
Attack and Defense Labs
宝玉的分享
宝玉的分享
AI
AI
Simon Willison's Weblog
Simon Willison's Weblog
C
Cyber Attacks, Cyber Crime and Cyber Security
I
Intezer
P
Proofpoint News Feed
Blog — PlanetScale
Blog — PlanetScale
Apple Machine Learning Research
Apple Machine Learning Research
Hugging Face - Blog
Hugging Face - Blog
The Last Watchdog
The Last Watchdog
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
Vercel News
Vercel News
I
InfoQ
阮一峰的网络日志
阮一峰的网络日志
Cisco Talos Blog
Cisco Talos Blog
W
WeLiveSecurity
Hacker News: Ask HN
Hacker News: Ask HN
Recent Commits to openclaw:main
Recent Commits to openclaw:main
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
D
Docker
博客园 - Franky
Security Archives - TechRepublic
Security Archives - TechRepublic

Vercel News

Vercel Open Source Program: Winter 2026 cohort How Notion Workers run untrusted code at scale with Vercel Sandbox How we run Vercel's CDN in front of Discourse From idea to secure checkout in minutes with Stripe Building Slack agents can be easy Scaling redirects to infinity on Vercel Advancing Python typing Gamma builds design-first agents with Vercel How Avalara turns pipe dreams into patent-pending with v0 Keeping community human while scaling with agents How OpenEvidence built a healthcare AI that physicians actually trust Security boundaries in agentic architectures Skills Night: 69,000+ ways agents are getting smarter Video Generation with AI Gateway We Ralph Wiggumed WebStreams to make them 10x faster How Stably ships AI testing agents in hours, not weeks How we built AEO tracking for coding agents Anyone can build agents, but it takes a platform to run them Introducing Geist Pixel The Vercel AI Accelerator is back with $6m in credits Making agent-friendly pages with content negotiation The Vercel OSS Bug Bounty program is now available Introducing the new v0 Run untrusted code with Vercel Sandbox, now generally available How Stripe built a game-changing app in a single flight with v0 How Sensay went from zero to product in six weeks AGENTS.md outperforms skills in our agent evals Agent skills explained: An FAQ Testing if "bash is all you need" AWS databases are now live on the Vercel Marketplace and v0 Use Perplexity Web Search with Vercel AI Gateway Introducing: React Best Practices Nick Bogaty joins Vercel as Chief Revenue Officer How Mux shipped durable video workflows with their @mux/ai SDK How to build agents with filesystems and bash How we made v0 an effective coding agent Stopping the slow death of internal tools Building AI-Generated Pixel Trading Cards with Vercel AI Gateway We removed 80% of our agent’s tools AI SDK 6 Our $1 million hacker challenge for React2Shell Cline now runs on Vercel AI Gateway How to prompt v0 Build smarter workflows with Notion and v0 Vercel launches partner certification Inside Workflow DevKit: How framework integrations work React2Shell Security Bulletin | Vercel Knowledge Base Billions of requests: Black Friday-Cyber Monday 2025 Investing in the Python ecosystem AWS Databases coming to the Vercel Marketplace How we built the v0 iOS app Workflow Builder: Build your own workflow automation platform Vercel Open Source Program: Fall 2025 cohort Self-driving infrastructure Vercel collaborates with Google for Gemini 3 Pro Preview launch Vercel: The anti-vendor-lock-in cloud How Nous Research used BotID to block automated abuse at scale How AI Gateway runs on Fluid compute What we learned building agents at Vercel Build and deploy data applications on Snowflake with v0 BotID Deep Analysis catches a sophisticated bot network in real-time Vercel achieves TISAX AL2 compliance to serve automotive partners Bun runtime on Vercel Functions David Totten Joins Vercel to Lead Global Field Engineering Vercel Ship AI 2025 recap You can just ship agents AI agents and services on the Vercel Marketplace Built-in durability: Introducing Workflow Development Kit Zero-config backends on Vercel AI Cloud Introducing Vercel Agent: Your new Vercel teammate Update regarding Vercel service disruption on October 20, 2025 Agents at work, a partnership with Salesforce and Slack Running Next.js in ChatGPT: How to Build ChatGPT Apps Talha Tariq joins Vercel as CTO of Security Just another (Black) Friday Server rendering benchmarks: Fluid Compute and Cloudflare Workers Towards the AI Cloud: Our Series F Collaborating with Anthropic on Claude Sonnet 4.5 to power intelligent coding agents Preventing the stampede: Request collapsing in the Vercel CDN BotID uncovers hidden SEO poisoning How we made global routing faster with Bloom filters What you need to know about vibe coding Scale to one: How Fluid solves cold starts Addressing security & quality issues with MCP tools - Vercel AI agents at scale: Rox’s Vercel-powered revenue operating system Agentic Infrastructure Zero Data Retention on AI Gateway Optimizing Vercel Sandbox snapshots How Waldium made a blog platform work for humans and AI alike How FLORA shipped a creative agent on Vercel's AI stack Agent responsibly Making Turborepo 96% faster with agents, sandboxes, and humans Unified reporting for all AI Gateway usage new.website joins forces with v0 SERHANT.'s playbook for rapid AI iteration Two startups at global scale without DevOps Chat SDK brings agents to your users 360 billion tokens, 3 million customers, 6 engineers Meet the 2026 Vercel AI Accelerator Cohort Build knowledge agents without embeddings
Stress testing Biome's noFloatingPromises lint rule
Dimitri MitropoulosSoftware Engineer · 2025-09-04 · via Vercel News

6 min read

Recently we partnered with the Biome team to strengthen their noFloatingPromises lint rule to catch more subtle edge cases. This rule prevents unhandled Promises, which can cause silent errors and unpredictable behavior. Once Biome had an early version ready, they asked if we could help stress test it with some test cases.

At Vercel, we know good tests require creativity just as much as attention to detail. To ensure strong coverage, we wanted to stretch the rule to its limits and so we thought it would be fun to turn this into a friendly internal competition. Who could come up with the trickiest examples that would still break the updated lint rule?

Part of the fun was learning together, but before we dive into the snippets, let’s revisit what makes a Promise “float”.

Link to headingWhat is a floating Promise?

A Promise is “floating” when it’s created in a way that its errors can never be handled or observed. A Promise is not considered floating if it’s awaited, assigned to a variable, returned from an async function, called with the void operator, or has .then(...).catch(...) handlers.

This lint rule is important because broken control flow and unhandled errors resulting from floating Promises are notoriously hard to catch. Many engineers have campfire stories of floating Promises taking down production.

With that in mind, let’s look at some of the edge cases our engineers came up with.

Link to headingArray of Promises

Let’s kick it off with a great example of “smarter not harder”. This snippet was taken directly from typescript-eslint’s docs for their floating Promises rule.

[1, 2, 3].map(async (x) => x + 1)

It might look harmless, but it's tricky because the array of Promises is never stored or awaited, leaving all inner Promises floating.

Link to headingPromise-like objects

Normally, TypeScript knows that if you return a Promise, a linter can catch it when it floats:

function normalPromise(): Promise<number> {

return new Promise((_, reject) => reject(2))

}

normalPromise() // linter warns: floating Promise

But if you return a PromiseLike (PromiseLike is a TypeScript built-in), it’s only structurally similar, not the real thing:

function promiseLike(): PromiseLike<number> {

return new Promise((_, reject) => reject(2))

}

promiseLike() // floating Promise

Since PromiseLike is only a structural match, calling promiseLike() and ignoring its rejection leaves an unhandled async result floating in space.

typescript-eslint handles this kind of case with a special configuration option for “Thenables” (another name for what PromiseLike represents)

Link to headingStructural typing tricks

By copying the TypeScript structure for a Promise under a different name, you can sneak past naïve checks.

/** a direct copy of the TypeScript `Promise` type, but with a different name */

interface Duck<T> {

then<TResult1 = T, TResult2 = never>(

onfulfilled?: ((value: T) => TResult1 | PromiseLike<TResult1>) | undefined | null,

onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | undefined | null

): Promise<TResult1 | TResult2>

catch<TResult = never>(onrejected?: ((reason: any) => TResult | PromiseLike<TResult>) | undefined | null): Promise<T | TResult>

}

function promise(): Duck<string> {

return new Promise((_, reject) => reject(2))

}

promise() // floating Promise (thenable)

You’ve made a new type called Duck that looks exactly like a Promise, just with a different name. Because TypeScript uses “structural” typing, Duck behaves like a Promise but slips past lint rules that only check names. The name itself is a nod to “duck typing”, referencing the old idiom “if it walks like a duck, and talks like a duck, then it's a duck”.

Link to headingConditional type aliases

Now we’re getting to the fun stuff: type-level trickery. Normally, TypeScript knows when you’re returning a Promise directly:

async function promiseLike() {

return new Promise((_, reject) => reject(2))

}

promiseLike() // linter warns: floating Promise

But if you wrap the Promise inside a generic alias with a conditional, it doesn’t look like a plain Promise anymore.

type Cheating<T extends 1> = T extends 1 ? Promise<string> : Promise<string>

async function promiseLike(): Cheating<1> {

return new Promise((_, reject) => reject(2))

}

promiseLike() // floating Promise

Although Cheating<T> always resolves to a Promise<string>, the conditional type and type parameter make that less obvious at the call site. If the lint rule only checks keys on the literal Promise name (instead of “thenables”), promiseLike(): Cheating<1> can slip past. The call to promiseLike() still returns a rejecting Promise, which is ignored and still floats.

Link to headingProxy-based Promises

The JavaScript Proxy object is useful to those that absolutely need it and incomprehensibly complex to everyone else. So it’s no wonder that we got one submission that ran with the idea “I bet I can use Proxy objects to break this”. This is perhaps the submission least likely to occur in production, but hey, a type-level hole is a type-level hole.

Normally, if you call methods on a Promise, the linter knows what’s going on:

new Promise((_, reject) => reject(2)).then(() => {})

But with JavaScript’s Proxy, you can intercept property access and sneak in hidden async behavior:

function createLazyPromise<

T extends string,

U extends (prop: PropertyKey) => Promise<T>,

>(getValue: U) {

let resolve: (value: T) => void

const promise = new Promise<T>((r) => {

resolve = r

return r

})

const proxy = new Proxy(promise as Promise<T>, {

get(target, prop, receiver) {

if (prop in target) {

return Reflect.get(target, prop, receiver)

}

// Access to any other property triggers resolution

getValue(prop).then(resolve) // floating promise

return undefined // Could also return another proxy here

},

})

return proxy as Promise<T>

}

const lazy = createLazyPromise((prop) =>

Promise.resolve(`You accessed: ${String(prop)}`),

)

lazy.then((result) => {

console.log(result) // floating Promise

})

(lazy as any).foo // floating Promise

Here, accessing any non-Promise property on lazy secretly triggers an async side effect that floats unhandled. Even the lazy.then(...) call returns a Promise that goes unhandled, compounding the drift. It’s a contrived example, but it shows how flexible (and fragile) type inference can be.

Link to headingFrozen Promise objects

Freezing a Promise changes its type in ways that complicate detection.

Object.freeze(new Promise((_, reject) => reject(2)))

The type of this expression is Readonly<Promise<unknown>>. That’s because Object.freeze() prevents writing on any object you pass it. It’s tricky because you’re wrapping the type with the Readonly utility type which makes it harder for a linter to catch.

Link to headingPromise-returning object members

Finally! A simple one. Wrapping a Promise in an object method hides it behind another layer.

const sneakyObject = {

rejectSomething() {

return new Promise((_, reject) => reject(2))

}

}

sneakyObject.rejectSomething() // floating Promise

Instead of relying on some kind of trick, this submission wraps the Promise in a function, rejectSomething, that is itself a member of sneakyObject.

Link to headingProperty getters

JavaScript getters can also hide Promises behind property access.

const sneakyObject2 = {

get something() {

return new Promise((_, reject) => reject(2))

},

}

sneakyObject2.something // floating Promise

Similar to the last example, you can use JavaScript’s get syntax to hide the floating Promise. At a glance it looks like a simple property, but it’s actually returning an unhandled Promise.

Link to headingType remapping with getters

Normally, accessing an object property feels safe. But with a mapped type, even a getter can hide a Promise. This snippet disguises an async call as a harmless property getter.

interface Things {

Thing: string

}

type CalculateGetter<T> = {

[K in keyof T as K extends string ? `get${K}` : never]: () => Promise<T[K]>

}

declare const lazyThings: CalculateGetter<Things>

lazyThings.getThing() // floating Promise

The mapped type manufactures get* methods that return Promises, but calling lazyThings.getThing() without await (or .then) leaves that Promise floating. It looks like a simple field read, yet the generic sleight of hand turns it into an unhandled async operation. Good luck ever catching this in code reviews!

Link to headingShort-circuit operators

Logical operators return values, not effects, so they can leave Promises dangling.

true && new Promise((_, reject) => reject(2)) // floating Promise

Classic short-circuit shenanigans: true && <Promise> evaluates to the right-hand side, yielding a Promise value in pure expression position. Since nothing awaits or .catches it, the rejection goes unhandled. It’s a reminder that && doesn’t run effects and wait. It actually returns a value, which here happens to be a volatile Promise.

Link to headingRandomized expressions

What if you only sometimes have a floating Promise? When randomness is involved, sometimes only part of the code returns a Promise.

Math.random() > 0.5

? new Promise((_, reject) => reject(2)) // floating Promise

: null

Maybe there’s some value that only exists at runtime, perhaps from user input or some API. In that case, it still should be a lint error. The type of this expression is Promise<unknown> | null - and that’s good enough to fit the bill!

Link to headingOptional chaining fallbacks

Optional chaining with fallbacks can produce Promises that go unhandled. Similar to the last two, you can trigger the “short circuiting” however you want, and this example uses optional chaining.

const optionalObject: Record<string, (() => unknown) | undefined> = {}

optionalObject?.nonExistentMethod?.() || new Promise((_, reject) => reject(2))

The optional call returns undefined, so || eagerly evaluates the right-hand side which constructs a rejecting Promise. Because that Promise lives only in expression position (never assigned, awaited, or .catched), the rejection floats silently behind an innocent-looking fallback.

Link to headingImmediately invoked functions

There was once a time when every JavaScript developer had to be aware of the immediately invoked function expression (IIFE, pronounced “if-y”)

(() => new Promise((_, reject) => reject(2)))()

Wrapping in a function call doesn’t change the fact that the Promise is unhandled.

Link to headingThe comma operator

Last up, we have the obscure comma operator. If you’ve ever looked at minified JavaScript you’ve likely seen this in action.

let _x = 5

_x++, new Promise((_, reject) => reject(2))

The result of the expression is the Promise, which is ignored and left floating. It’s a syntactically tight way to discard the left expression and return whatever’s on the right. It once had niche uses, but today it’s mostly syntactic trivia. Still, it’s one more case a linter has to catch.

Link to headingWinner

After consideration from an esteemed panel of judges, it was decided that the Proxy Promise submission was the winner. It was the least practical, most convoluted, and most obscure example. But that's exactly what we were looking for. The goal was never to find real-world bugs, but to stress test the implementation with any trick we could imagine.

These snippets helped the Biome maintainers quickly fix issues, many of which are now resolved today. Like any software, linters need to prioritize the cases most likely to affect users. If you have an edge case of your own that isn't fixed, consider sending Biome a PR!

Link to headingJoin us

This competition was just as much about culture as it was about improving the lint rule. It gave us the chance to collaborate, get creative, support open source, and share in some friendly mischief. That reflects the culture we're building at Vercel: solving hard problems together while having fun along the way.

Our engineers care deeply about improving the developer experience, building fast and reliable systems, and giving back to the open source community. We thrive on curiosity, creativity, and collaboration, whether that’s designing scalable infrastructure, pushing the boundaries of web performance, or inventing new ways to make developers more productive.

If that sounds like you, we’d love to work together. Explore open roles at Vercel.