Skip to content

Commit 423eddf

Browse files
committed
fix: convert createProfile's raw ZodError throw into ConfigValidationError
createProfile called ConfigProfileSchema.parse() directly on the --extends list, so a malformed entry (e.g. an empty name produced by a stray double-comma in --extends "a,,b") crashed with a raw ZodError stack trace instead of the clean message every other config-write path in this codebase gives. createProfile now safeParses and throws ConfigValidationError, matching readJson/applyPatch/loadConfigFile's existing pattern.
1 parent 74cfe16 commit 423eddf

2 files changed

Lines changed: 13 additions & 4 deletions

File tree

src/configProfiles.test.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,10 @@ describe("configProfiles", () => {
4949
createProfile(paths, "base");
5050
expect(() => createProfile(paths, "base")).toThrow(ProfileAlreadyExistsError);
5151
});
52+
53+
it("throws ConfigValidationError, not a raw ZodError, for an extends list containing an empty name (e.g. from a stray `,,` in --extends)", () => {
54+
expect(() => createProfile(paths, "work", ["base", "", "other"])).toThrow(ConfigValidationError);
55+
});
5256
});
5357

5458
describe("readProfile", () => {

src/configProfiles.ts

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import {
1616
} from "./config/schema";
1717
import { collectBoolPairs } from "./cli/parsers";
1818
import { CliError } from "./cliError";
19+
import { ConfigValidationError } from "./config/load";
1920
import { realPromptsPort, runProfileWizard } from "./configure";
2021
import type { LayoutPaths } from "./paths";
2122

@@ -64,17 +65,21 @@ export function readProfile(paths: LayoutPaths, name: string): ConfigProfile | u
6465
}
6566

6667
/**
67-
* Creates a new, empty configuration profile (optionally extending others). Throws `ProfileAlreadyExistsError` if a profile with this name already has a file.
68+
* Creates a new, empty configuration profile (optionally extending others). Throws `ProfileAlreadyExistsError` if a profile with this name already has a file, and `ConfigValidationError` when `extendsList` fails `ConfigProfileSchema` (e.g. contains an empty name from a stray `,,` in `--extends`), rather than letting the underlying `ZodError` escape as an unhandled crash.
6869
*/
6970
export function createProfile(paths: LayoutPaths, name: string, extendsList?: readonly string[]): ConfigProfile {
7071
if (profileExists(paths, name)) {
7172
throw new ProfileAlreadyExistsError(name);
7273
}
73-
const profile = ConfigProfileSchema.parse(
74+
const filePath = profileJsonPath(paths, name);
75+
const parsed = ConfigProfileSchema.safeParse(
7476
extendsList !== undefined && extendsList.length > 0 ? { extends: [...extendsList] } : {},
7577
);
76-
writeJsonAtomic(profileJsonPath(paths, name), profile);
77-
return profile;
78+
if (!parsed.success) {
79+
throw new ConfigValidationError(filePath, parsed.error.issues);
80+
}
81+
writeJsonAtomic(filePath, parsed.data);
82+
return parsed.data;
7883
}
7984

8085
/** One profile as reported by `listProfiles`. */

0 commit comments

Comments
 (0)