TypeScript

Fix "No license field" when package.json has a license

Read the path in the warning, find the stray package.json above your project, and silence the line without inventing an open-source licence.

Mahdi Ben RhoumaMahdi Ben Rhouma
7 min read

TL;DR#

When Yarn prints warning ../package.json: No license field, the ../ is the whole story: the file it complains about sits one directory above your project, not inside it. Yarn classic walks up the directory tree from where you run it and validates every package.json it meets. The usual culprit is an old, forgotten package.json in your home folder. Your own "license": "UNLICENSED" is valid and is not the problem.

Fix the file the warning names: delete it if it should not be there, or add "private": true (or a license) to it. Leave your project's package.json alone.

The report comes from a Stack Overflow question where the project declared "license": "UNLICENSED" and Yarn 0.27.5 still printed this on every install:

text
yarn install v0.27.5
warning ../package.json: No license field
[1/4] Resolving packages...
success Already up-to-date.
Done in 0.09s.

Why the warning points above your project#

The accepted answer on the question found the cause: a stale ~/package.json in the home folder, with no license, above ~/my-project/package.json. The Yarn classic source shows why that parent file is read at all.

Before installing, Yarn looks for a workspace root. Its findWorkspaceRoot function in src/config.js starts at the current directory and moves to the parent, then the grandparent, until it reaches the filesystem root or a package.json that declares workspaces. In every directory it reads package.json with the "root" flag set, and that runs the full manifest validation.

The validation lives in src/util/normalize-manifest/validate.js:

js
// validate license
if (isRoot && !info.private) {
  if (typeof info.license === 'string') {
    const license = info.license.replace(/\*$/g, '');
    if (!isValidLicense(license)) {
      warn(reporter.lang('manifestLicenseInvalid'));
    }
  } else {
    warn(reporter.lang('manifestLicenseNone'));
  }
}

The two message keys map to the strings in src/reporters/lang/en.js: manifestLicenseNone is "No license field" and manifestLicenseInvalid is "License should be a valid SPDX license expression". The prefix comes from normalize-manifest/index.js: for a root manifest, Yarn replaces the package name with the file's path relative to where you ran the command. Your own file shows as package.json, its parent as ../package.json, the grandparent as ../../package.json.

Two consequences follow from that code. First, "private": true on a file switches the check off for that file. Second, the walk does not stop at your project: every directory up to the filesystem root is visited unless a manifest that declares workspaces ends it earlier (that stopping rule is read from the source, not tested here).

Your UNLICENSED value is fine. The npm package.json reference says: "Finally, if you do not wish to grant others the right to use a private or unpublished package under any terms:" followed by { "license": "UNLICENSED" }, and adds: "Consider also setting "private": true to prevent accidental publication."

The same layout, reproduced#

The question's layout was rebuilt on 19 October 2026 in the official node:22-alpine Docker image (Node 22.23.3, Yarn 1.22.22, npm 10.9.9): a license-less /work/package.json above a project at /work/app with "license": "UNLICENSED". The container ran without network access, which explains Yarn's extra "internet connection" line; it has nothing to do with licences.

text
$ cat /work/package.json
{
  "name": "forgotten-parent",
  "version": "1.0.0"
}
$ cat /work/app/package.json
{
  "name": "license-example",
  "version": "1.0.0",
  "license": "UNLICENSED"
}
$ yarn install
yarn install v1.22.22
warning You don't appear to have an internet connection. Try the --offline flag to use the cache for registry queries.
warning ../package.json: No license field
info No lockfile found.

Same line as in 2017, same cause: the project's own file passes, and the parent file is reported.

Fix: change the file the path names#

  1. Read the path before the colon. package.json: is your project. ../package.json: is the parent directory, ../../package.json: the one above it. Only the first case is about your own file.

  2. List every package.json above the current directory. Run this from the project root (POSIX shell, so macOS, Linux, WSL or Git Bash):

    bash
    d="$PWD"
    while [ "$d" != "/" ]; do
      d="$(dirname "$d")"
      [ -f "$d/package.json" ] && echo "${d%/}/package.json"
    done

    With stray files at /work and at /, it prints both, and Yarn warns once per file:

    text
    /work/package.json
    /package.json
    $ yarn install
    yarn install v1.22.22
    warning You don't appear to have an internet connection. Try the --offline flag to use the cache for registry queries.
    warning ../package.json: No license field
    warning ../../package.json: No license field
  3. Delete the stray file if nothing uses it. In the accepted answer it was an outdated, forgotten package.json in the home folder. First check whether a lockfile or a node_modules folder sits next to it, which would mean something was installed there:

    bash
    ls ~/package.json ~/package-lock.json ~/yarn.lock ~/node_modules 2>/dev/null

    Then remove the file step 2 printed (here the home-folder example):

    bash
    rm ~/package.json
  4. Or mark it private if the parent is real. When the parent directory is a genuine project (a monorepo shell, a folder of scripts), keep the file and add "private": true to it, or give it a real license:

    json
    {
      "name": "forgotten-parent",
      "version": "1.0.0",
      "private": true
    }

Do not add another licence to your own project to silence a ../ warning: the project already passes, and changing it does not touch the file Yarn is reading.

Verify the fix#

Run yarn install again in the project. In the reproduction, adding "private": true to the parent file was the only change to either package.json (the lockfile from the first run was removed so each run started fresh), and the warning disappeared:

text
$ yarn install
yarn install v1.22.22
warning You don't appear to have an internet connection. Try the --offline flag to use the cache for registry queries.
info No lockfile found.
[1/4] Resolving packages...
[2/4] Fetching packages...
[3/4] Linking dependencies...
[4/4] Building fresh packages...
success Saved lockfile.
Done in 0.10s.

Deleting the parent file instead gave the same clean output. If a ../../ line is still there, step 2 will show the next file up.

One email a month — the latest explained errors

What the site published that month — mostly Next.js, Supabase and Node errors, explained. You confirm by email; unsubscribe any time in one click.

When the path is your own package.json#

If the warning reads package.json: with no ../, the project's own file really has no usable licence. In the same container, a project with no license field printed the warning twice, once by path and once by name:

text
warning package.json: No license field
info No lockfile found.
warning license-example@1.0.0: No license field

A free-text value does not count as a licence. "license": "Proprietary" produced the second message from the source:

text
warning package.json: License should be a valid SPDX license expression
info No lockfile found.
warning license-example@1.0.0: License should be a valid SPDX license expression

Three values passed without a warning in the same test:

  • "license": "UNLICENSED", for code nobody else may use;
  • "license": "SEE LICENSE IN LICENSE.txt", the form the npm docs give for a custom licence ("use a string value like this one" followed by SEE LICENSE IN <filename>). Yarn only checks the string, and no LICENSE.txt existed in the test; the npm docs separately tell you to include that file at the top level of the package;
  • no license at all, but "private": true.

For an internal company project, UNLICENSED plus "private": true is the combination the npm documentation points to. The private field means "npm will refuse to publish it", which protects the code as well as quietening Yarn. A related question, what to put in the license field for company-only code, lands on the same values.

What npm does with the same files#

The question says "npm/yarn", and the accepted answer says both tools look in parent directories. For this warning, the test did not bear that out on npm.

npm 6.14.18 (official node:14-alpine image), with the same license-less parent and a project set to UNLICENSED, printed nothing about licences. It only warned when the project itself had no licence, and the line has no path in it and ends with a full stop. The project used in that run:

text
$ cat /work/app/package.json
{
  "name": "license-example",
  "version": "1.0.0",
  "description": "demo",
  "repository": "github:example/license-example"
}
$ npm install
npm notice created a lockfile as package-lock.json. You should commit this file.
npm WARN license-example@1.0.0 No license field.

Adding "private": true to that project removed the line. The test project also had a description and a repository so that the licence warning stood alone; on a bare package.json, npm 6 also prints No description and No repository field warnings, and the same "private": true silences those too.

npm 10.9.9, with a license-less parent and a license-less project, printed only up to date during npm install. In this test neither npm 6.14.18 nor npm 10.9.9 printed a ../ path: that prefix comes from Yarn classic's manifest normaliser, shown above.

Other package.json checks that read the wrong file#

The pattern (a warning or error about a package.json you did not expect) also shows up with versions. npm rejects a short version such as "1" and names the file it read; the Invalid version: "1" guide shows how to find which package.json carries it. And if your npm 6 install output is still noisy after the licence line is gone, the remaining requires a peer of lines are a different matter, covered in npm WARN requires a peer of X but none is installed.

The licence warning itself never blocks an install. It is Yarn telling you that some package.json on the path to the filesystem root has no valid licence. Read the relative path, fix that file, and keep UNLICENSED where you put it.

Further reading: Fix grpc-tools 404 on darwin-arm64.tar.gz (Mac M1). Also see Fix Failed to replace env in config: NPM_TOKEN.

Frequently Asked Questions

|

Have more questions? Contact us

Still stuck? Paste your error.

Paste the error message or stack trace — we check it against every fix and tool on the site.

Matching happens in your browser. When you search, a cleaned error signature is sent so we can spot errors we do not cover yet — never the raw text, your IP address or your e-mail. Do not paste passwords or keys. Details

Written by

Mahdi Ben Rhouma
Mahdi Ben Rhouma

Full-Stack Dev — Next.js & Supabase

Solo developer building SaaS products with Next.js and Supabase. Writing about production patterns the official docs skip.

Remote