--- title: Yarn 4.16 npmMinimalAgeGate — YN0016 "quarantined" на свежих пакетах type: concept tags: [yarn, yarn-berry, verdaccio, npm, supply-chain, gotcha, YN0016, age-gate] sources: [] updated: 2026-06-11 --- # Yarn 4.16 `npmMinimalAgeGate` — клиентский «карантин» свежих версий ## Симптом `yarn install` (Yarn Berry **≥4.16**) падает на резолве: ``` @snolla/site-schema-gen@npm:^0.5.0: All versions satisfying "^0.5.0" are quarantined ``` Код ошибки — **YN0016**. Версия физически есть в реестре, `dist-tags.latest` указывает на неё, токен валиден (`whoami` отдаёт юзера) — но yarn её не берёт. ## Root cause — клиентский age-gate, НЕ сервер Yarn 4.16 ввёл настройку **`npmMinimalAgeGate`** (supply-chain мера против свежезалитых вредоносных версий, по следам атак на npm 2025). Из бинаря `~/AppData/Local/node/corepack/v1/yarn/4.16.0/yarn.js`: ``` npmMinimalAgeGate: { type: "DURATION", unit: "m", default: "1d" } # = 1440 минут ``` Фильтр перед резолвом отсеивает версию, если: - у неё нет даты публикации в packument-поле `time`, **или** - `(now − publishDate) < npmMinimalAgeGate`. Если после фильтра кандидатов не осталось → `throw YN0016 "...are quarantined"`. **Карантин целиком на стороне yarn-клиента.** На сервере verdaccio никакого карантина нет (нет в `config.yaml`, plugins-папка пустая) — серверная проверка пакумента его не видит. Реестр отдаёт версию чисто любому валидному read-токену. ## Версионная разница (почему «у одних работает») | yarn | `npmMinimalAgeGate` default | |---|---| | ≤ 4.14 (напр. snolla 4.14.1) | `0` — гейта нет | | ≥ 4.16 | `1d` (1440 мин) | Проект на 4.14 «просто работает», на 4.16 тот же канон ловит YN0016 первые 24 ч после публикации пакета. ## Два независимых последовательных гейта Важно не путать с auth — это разные стены, в таком порядке: 1. **auth** — кривой/протухший токен → `YN0041 Invalid authentication` (это 401, см. [[verdaccio-token-lifecycle]]). 2. **age-gate** — валидный токен, но версия моложе порога → `YN0016 …quarantined`. Решающий признак: если на **валидном** токене (auth прошёл, 401 нет) всё равно падает — это гейт #2, не auth. Token-fix его НЕ снимает. ## Fix ```yaml # .yarnrc.yml — глобально: npmMinimalAgeGate: 0 ``` ```bash # либо разово, per-invocation (сохраняет защитный дефолт для обычных install'ов): YARN_NPM_MINIMAL_AGE_GATE=0 yarn install ``` ### Нюанс: гейт читается ГЛОБАЛЬНО, не per-scope В фильтре — `configuration.get("npmMinimalAgeGate")` (глобальный config), не scope-aware lookup. Поэтому `npmMinimalAgeGate` под `npmScopes.@snolla.*` **игнорируется** — нельзя ослабить гейт только для доверенного приватного скоупа. Глобальный `0` снимает age-защиту и с **публичных** npmjs-пакетов, которые verdaccio проксирует через uplink. Это реальный security trade-off — в этом и смысл фичи. **Рекомендация:** не коммитить `0` в общий канон бездумно. Для CI / чужих проектов — разовый `YARN_NPM_MINIMAL_AGE_GATE=0` под осознанный install сразу после своей публикации. Для тесного publish→consume dev-loop своих пакетов (напр. pilonuxt) глобальный `0` оправдан — реестр один доверенный, DX важнее. Финальный risk-call — за владельцем экосистемы. ## Ecosystem heads-up Любой потребитель на **yarn ≥4.16**, тянущий свежеопубликованные `@snolla`/`@snollajs` пакеты, будет ловить YN0016 первые 24 ч. Когда snolla-монореп/проекты переедут на 4.16+ — решить, добавлять ли `npmMinimalAgeGate: 0` в snolla-канон `.yarnrc.yml` или держать override on-demand. ## Применено / источник Диагностировано 2026-06-11 совместно с сессией pilonuxt (миграция pnpm→yarn 4.16). Первичная ошибочная гипотеза «карантин = серверный дефект verdaccio» опровергнута: пруф — строка `are quarantined` + `npmMinimalAgeGate` в `yarn.js` 4.16.0, и YN0016 воспроизводится на валидном vitya-токене, снимается только `npmMinimalAgeGate: 0`. ## Связанные - [[verdaccio-token-lifecycle]] — гейт #1 (auth / JWT / 401), соседняя стена - [[verdaccio-restore-packument-desync]] — почему версии вообще пришлось republish (disaster-restore) - [[../entities/vds-kzntsv]] — хост verdaccio