Compare commits

...

3 Commits

Author SHA1 Message Date
Jarred Sumner
2c5da98665 Merge branch 'main' into claude/fix-missing-package-json-error-message 2026-01-16 16:24:20 -08:00
Jarred Sumner
f7df2af737 Merge branch 'main' into claude/fix-missing-package-json-error-message 2026-01-14 18:40:55 -08:00
Claude Bot
42c3217f79 fix(install): show folder path in MissingPackageJSON error
When `bun install` encounters a local folder dependency without a
package.json, the error message now includes the folder path that's
missing, making it easier to debug which dependency failed.

Before: `error: MissingPackageJSON`
After: `error: no package.json file found for dependency "lodash" in ./doesnotexist`

Fixes #2451

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-15 01:01:33 +00:00
3 changed files with 86 additions and 2 deletions

View File

@@ -64,6 +64,30 @@ pub fn enqueueDependencyList(
resolution,
false,
) catch |err| {
// For MissingPackageJSON on folder dependencies, show the folder path that's missing
if (err == error.MissingPackageJSON and dependency.version.tag == .folder) {
const folder_path = lockfile.str(&dependency.version.value.folder);
const dep_name = lockfile.str(&dependency.realname());
if (dependency.behavior.isOptional() or dependency.behavior.isPeer()) {
this.log.addWarningFmt(
null,
.{},
this.allocator,
"no package.json file found for dependency \"{s}\" in {f}",
.{ dep_name, bun.fmt.fmtPath(u8, folder_path, .{ .path_sep = .auto }) },
) catch unreachable;
} else {
this.log.addErrorFmt(
null,
.{},
this.allocator,
"no package.json file found for dependency \"{s}\" in {f}",
.{ dep_name, bun.fmt.fmtPath(u8, folder_path, .{ .path_sep = .auto }) },
) catch unreachable;
}
continue;
}
const note = .{
.fmt = "error occurred while resolving {f}",
.args = .{bun.fmt.fmtPath(u8, lockfile.str(&dependency.realname()), .{

View File

@@ -111,8 +111,8 @@ it("should reject missing package", async () => {
env,
});
const err = await stderr.text();
expect(err).toContain("error: MissingPackageJSON");
expect(err).toContain(`note: error occurred while resolving file:${add_path}`);
expect(err).toContain("no package.json file found");
expect(err).toContain(add_path);
const out = await stdout.text();
expect(out).toEqual(expect.stringContaining("bun add v1."));

View File

@@ -0,0 +1,60 @@
import { expect, test } from "bun:test";
import { bunEnv, bunExe, tempDir } from "harness";
// https://github.com/oven-sh/bun/issues/2451
// bun install should show the folder path when a local dependency is missing a package.json
test("bun install shows folder path for missing package.json in folder dependency", async () => {
using dir = tempDir("issue-2451", {
"package.json": JSON.stringify({
name: "test-pkg",
version: "1.0.0",
dependencies: {
"my-local-dep": "./doesnotexist",
},
}),
});
await using proc = Bun.spawn({
cmd: [bunExe(), "install"],
cwd: String(dir),
env: bunEnv,
stdout: "pipe",
stderr: "pipe",
});
const [stdout, stderr, exitCode] = await Promise.all([proc.stdout.text(), proc.stderr.text(), proc.exited]);
// The error message should contain the folder path that's missing
expect(stderr).toContain("doesnotexist");
expect(stderr).toContain("my-local-dep");
expect(stderr).toContain("no package.json");
expect(exitCode).toBe(1);
});
test("bun install shows folder path for missing package.json with relative path", async () => {
using dir = tempDir("issue-2451-relative", {
"package.json": JSON.stringify({
name: "test-pkg",
version: "1.0.0",
dependencies: {
"local-lib": "../nonexistent-lib",
},
}),
});
await using proc = Bun.spawn({
cmd: [bunExe(), "install"],
cwd: String(dir),
env: bunEnv,
stdout: "pipe",
stderr: "pipe",
});
const [stdout, stderr, exitCode] = await Promise.all([proc.stdout.text(), proc.stderr.text(), proc.exited]);
// The error message should contain the folder path
expect(stderr).toContain("nonexistent-lib");
expect(stderr).toContain("local-lib");
expect(stderr).toContain("no package.json");
expect(exitCode).toBe(1);
});