fix(errors): Deprecate error codes (#7347)

Co-authored-by: bluwy <bjornlu.dev@gmail.com>
This commit is contained in:
Erika 2023-06-26 10:51:06 +02:00 committed by GitHub
parent 39a24f111d
commit 4e02a59e42
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
18 changed files with 44 additions and 195 deletions

View file

@ -371,7 +371,6 @@ function stringifyEntryData(data: Record<string, any>): string {
}); });
} else { } else {
throw new AstroError({ throw new AstroError({
code: 99999,
message: 'Unexpected error processing content collection data.', message: 'Unexpected error processing content collection data.',
}); });
} }

View file

@ -82,7 +82,6 @@ function handleCompileResultErrors(result: TransformResult, cssTransformErrors:
if (compilerError) { if (compilerError) {
throw new CompilerError({ throw new CompilerError({
code: compilerError.code,
message: compilerError.text, message: compilerError.text,
location: { location: {
line: compilerError.location.line, line: compilerError.location.line,
@ -98,15 +97,11 @@ function handleCompileResultErrors(result: TransformResult, cssTransformErrors:
break; break;
case 1: { case 1: {
const error = cssTransformErrors[0]; const error = cssTransformErrors[0];
if (!error.errorCode) {
error.errorCode = AstroErrorData.UnknownCSSError.code;
}
throw cssTransformErrors[0]; throw cssTransformErrors[0];
} }
default: { default: {
throw new AggregateError({ throw new AggregateError({
...cssTransformErrors[0], ...cssTransformErrors[0],
code: cssTransformErrors[0].errorCode,
errors: cssTransformErrors, errors: cssTransformErrors,
}); });
} }

View file

@ -88,7 +88,6 @@ function enhanceCSSError(err: any, filename: string) {
errorPosition.line += 1; errorPosition.line += 1;
return new CSSError({ return new CSSError({
code: AstroErrorData.UnknownCSSError.code,
message: err.message, message: err.message,
location: { location: {
file: filename, file: filename,

View file

@ -10,7 +10,7 @@
Name (key of the object definition): Name (key of the object definition):
- As with the error code, this property is a static reference to the error. The shape should be similar to JavaScript's native errors (TypeError, ReferenceError): pascal-cased, no spaces, no special characters etc. (ex: `ClientAddressNotAvailable`) - This property is a static reference to the error. The shape should be similar to JavaScript's native errors (TypeError, ReferenceError): pascal-cased, no spaces, no special characters etc. (ex: `ClientAddressNotAvailable`)
- This is the only part of the error message that should not be written as a full, proper sentence complete with Capitalization and end punctuation. - This is the only part of the error message that should not be written as a full, proper sentence complete with Capitalization and end punctuation.
Title: Title:
@ -35,24 +35,7 @@ Hint:
- Describe the _what_, _why_ and _action to take_ from the user's perspective. Assume they don't know Astro internals, and care only about how Astro is _used_. (ex: `You are missing...` vs `Astro/file cannot find...`) - Describe the _what_, _why_ and _action to take_ from the user's perspective. Assume they don't know Astro internals, and care only about how Astro is _used_. (ex: `You are missing...` vs `Astro/file cannot find...`)
- Avoid using cutesy language. (ex: Oops!) This tone minimizes the significance of the error, which _is_ important to the developer. The developer may be frustrated and your error message shouldn't be making jokes about their struggles. Only include words and phrases that help the developer **interpret the error** and **fix the problem**. - Avoid using cutesy language. (ex: Oops!) This tone minimizes the significance of the error, which _is_ important to the developer. The developer may be frustrated and your error message shouldn't be making jokes about their struggles. Only include words and phrases that help the developer **interpret the error** and **fix the problem**.
**Choosing an Error Code** If you are unsure about anything, ask [Erika](https://github.com/Princesseuh)!
Choose any available error code in the appropriate range:
- 01xxx and 02xxx are reserved for compiler errors and warnings respectively
- 03xxx: Astro errors (your error most likely goes here!)
- 04xxx: Vite errors
- 05xxx: CSS errors
- 06xxx: Markdown errors
- 07xxx: Configuration errors
- 07xxx-98xxx <- Need to add a category? Add it here!
- 99xxx: Catch-alls for unknown errors
As long as it is unique, the exact error code used is unimportant. For example, error 5005 and error 5006 don't necessarily have to be related, or follow any logical pattern.
Users are not reading codes sequentially. They're much more likely to directly land on the error or search for a specific code.
If you are unsure about which error code to choose, ask [Erika](https://github.com/Princesseuh)!
### CLI specifics tips: ### CLI specifics tips:
@ -61,7 +44,7 @@ If you are unsure about which error code to choose, ask [Erika](https://github.c
### Shape ### Shape
- **Error codes and names are permanent**, and should never be changed, nor deleted. Users should always be able to find an error by searching, and this ensures a matching result. When an error is no longer relevant, it should be deprecated, not removed. - **Names are permanent**, and should never be changed, nor deleted. Users should always be able to find an error by searching, and this ensures a matching result. When an error is no longer relevant, it should be deprecated, not removed.
- Contextual information may be used to enhance the message or the hint. However, the code that caused the error or the position of the error should not be included in the message as they will already be shown as part of the error. - Contextual information may be used to enhance the message or the hint. However, the code that caused the error or the position of the error should not be included in the message as they will already be shown as part of the error.
- Do not prefix `title`, `message` and `hint` with descriptive words such as "Error:" or "Hint:" as it may lead to duplicated labels in the UI / CLI. - Do not prefix `title`, `message` and `hint` with descriptive words such as "Error:" or "Hint:" as it may lead to duplicated labels in the UI / CLI.
- Dynamic error messages must use the following shape: - Dynamic error messages must use the following shape:
@ -78,7 +61,7 @@ Using light logic to add / remove different parts of the message is okay, howeve
### Documentation support through JSDoc ### Documentation support through JSDoc
Using JSDoc comments, [a reference for every error message](https://docs.astro.build/en/reference/error-reference/) is built automatically on our docs. Users can then search for a error code to find more information on how to fix the error they encountered. Using JSDoc comments, [a reference for every error message](https://docs.astro.build/en/reference/error-reference/) is built automatically on our docs.
Here's how to create and format the comments: Here's how to create and format the comments:

View file

@ -45,7 +45,6 @@ export function enhanceViteSSRError({
safeError.name = 'FailedToLoadModuleSSR'; safeError.name = 'FailedToLoadModuleSSR';
safeError.message = AstroErrorData.FailedToLoadModuleSSR.message(importName); safeError.message = AstroErrorData.FailedToLoadModuleSSR.message(importName);
safeError.hint = AstroErrorData.FailedToLoadModuleSSR.hint; safeError.hint = AstroErrorData.FailedToLoadModuleSSR.hint;
safeError.code = AstroErrorData.FailedToLoadModuleSSR.code;
const line = lns.findIndex((ln) => ln.includes(importName!)); const line = lns.findIndex((ln) => ln.includes(importName!));
if (line !== -1) { if (line !== -1) {
@ -84,7 +83,6 @@ export function enhanceViteSSRError({
safeError.message = AstroErrorData.InvalidGlob.message(globPattern); safeError.message = AstroErrorData.InvalidGlob.message(globPattern);
safeError.name = 'InvalidGlob'; safeError.name = 'InvalidGlob';
safeError.hint = AstroErrorData.InvalidGlob.hint; safeError.hint = AstroErrorData.InvalidGlob.hint;
safeError.code = AstroErrorData.InvalidGlob.code;
safeError.title = AstroErrorData.InvalidGlob.title; safeError.title = AstroErrorData.InvalidGlob.title;
const line = lns.findIndex((ln) => ln.includes(globPattern)); const line = lns.findIndex((ln) => ln.includes(globPattern));
@ -139,17 +137,7 @@ export async function getViteErrorPayload(err: ErrorWithMetadata): Promise<Astro
const message = renderErrorMarkdown(err.message.trim(), 'html'); const message = renderErrorMarkdown(err.message.trim(), 'html');
const hint = err.hint ? renderErrorMarkdown(err.hint.trim(), 'html') : undefined; const hint = err.hint ? renderErrorMarkdown(err.hint.trim(), 'html') : undefined;
const hasDocs = const hasDocs = err.name in AstroErrorData;
(err.type &&
err.name && [
'AstroError',
'AggregateError',
/* 'CompilerError' ,*/
'CSSError',
'MarkdownError',
]) ||
['FailedToLoadModuleSSR', 'InvalidGlob'].includes(err.name);
const docslink = hasDocs const docslink = hasDocs
? `https://docs.astro.build/en/reference/errors/${getKebabErrorName(err.name)}/` ? `https://docs.astro.build/en/reference/errors/${getKebabErrorName(err.name)}/`
: undefined; : undefined;

View file

@ -5,7 +5,6 @@
import type { ZodError } from 'zod'; import type { ZodError } from 'zod';
export interface ErrorData { export interface ErrorData {
code: number;
title: string; title: string;
message?: string | ((...params: any) => string); message?: string | ((...params: any) => string);
hint?: string | ((...params: any) => string); hint?: string | ((...params: any) => string);
@ -30,7 +29,6 @@ export const AstroErrorData = {
*/ */
UnknownCompilerError: { UnknownCompilerError: {
title: 'Unknown compiler error.', title: 'Unknown compiler error.',
code: 1000,
hint: 'This is almost always a problem with the Astro compiler, not your code. Please open an issue at https://astro.build/issues/compiler.', hint: 'This is almost always a problem with the Astro compiler, not your code. Please open an issue at https://astro.build/issues/compiler.',
}, },
// 1xxx and 2xxx codes are reserved for compiler errors and warnings respectively // 1xxx and 2xxx codes are reserved for compiler errors and warnings respectively
@ -47,7 +45,6 @@ export const AstroErrorData = {
*/ */
StaticRedirectNotAvailable: { StaticRedirectNotAvailable: {
title: '`Astro.redirect` is not available in static mode.', title: '`Astro.redirect` is not available in static mode.',
code: 3001,
message: message:
"Redirects are only available when using `output: 'server'` or `output: 'hybrid'`. Update your Astro config if you need SSR features.", "Redirects are only available when using `output: 'server'` or `output: 'hybrid'`. Update your Astro config if you need SSR features.",
hint: 'See https://docs.astro.build/en/guides/server-side-rendering/#enabling-ssr-in-your-project for more information on how to enable SSR.', hint: 'See https://docs.astro.build/en/guides/server-side-rendering/#enabling-ssr-in-your-project for more information on how to enable SSR.',
@ -62,7 +59,6 @@ export const AstroErrorData = {
*/ */
ClientAddressNotAvailable: { ClientAddressNotAvailable: {
title: '`Astro.clientAddress` is not available in current adapter.', title: '`Astro.clientAddress` is not available in current adapter.',
code: 3002,
message: (adapterName: string) => message: (adapterName: string) =>
`\`Astro.clientAddress\` is not available in the \`${adapterName}\` adapter. File an issue with the adapter to add support.`, `\`Astro.clientAddress\` is not available in the \`${adapterName}\` adapter. File an issue with the adapter to add support.`,
}, },
@ -78,7 +74,6 @@ export const AstroErrorData = {
*/ */
StaticClientAddressNotAvailable: { StaticClientAddressNotAvailable: {
title: '`Astro.clientAddress` is not available in static mode.', title: '`Astro.clientAddress` is not available in static mode.',
code: 3003,
message: message:
"`Astro.clientAddress` is only available when using `output: 'server'` or `output: 'hybrid'`. Update your Astro config if you need SSR features.", "`Astro.clientAddress` is only available when using `output: 'server'` or `output: 'hybrid'`. Update your Astro config if you need SSR features.",
hint: 'See https://docs.astro.build/en/guides/server-side-rendering/#enabling-ssr-in-your-project for more information on how to enable SSR.', hint: 'See https://docs.astro.build/en/guides/server-side-rendering/#enabling-ssr-in-your-project for more information on how to enable SSR.',
@ -92,7 +87,6 @@ export const AstroErrorData = {
*/ */
NoMatchingStaticPathFound: { NoMatchingStaticPathFound: {
title: 'No static path found for requested path.', title: 'No static path found for requested path.',
code: 3004,
message: (pathName: string) => message: (pathName: string) =>
`A \`getStaticPaths()\` route pattern was matched, but no matching static path was found for requested path \`${pathName}\`.`, `A \`getStaticPaths()\` route pattern was matched, but no matching static path was found for requested path \`${pathName}\`.`,
hint: (possibleRoutes: string[]) => hint: (possibleRoutes: string[]) =>
@ -120,7 +114,6 @@ export const AstroErrorData = {
*/ */
OnlyResponseCanBeReturned: { OnlyResponseCanBeReturned: {
title: 'Invalid type returned by Astro page.', title: 'Invalid type returned by Astro page.',
code: 3005,
message: (route: string | undefined, returnedValue: string) => message: (route: string | undefined, returnedValue: string) =>
`Route \`${ `Route \`${
route ? route : '' route ? route : ''
@ -140,7 +133,6 @@ export const AstroErrorData = {
*/ */
MissingMediaQueryDirective: { MissingMediaQueryDirective: {
title: 'Missing value for `client:media` directive.', title: 'Missing value for `client:media` directive.',
code: 3006,
message: message:
'Media query not provided for `client:media` directive. A media query similar to `client:media="(max-width: 600px)"` must be provided', 'Media query not provided for `client:media` directive. A media query similar to `client:media="(max-width: 600px)"` must be provided',
}, },
@ -157,7 +149,6 @@ export const AstroErrorData = {
*/ */
NoMatchingRenderer: { NoMatchingRenderer: {
title: 'No matching renderer found.', title: 'No matching renderer found.',
code: 3007,
message: ( message: (
componentName: string, componentName: string,
componentExtension: string | undefined, componentExtension: string | undefined,
@ -192,7 +183,6 @@ but ${plural ? 'none were' : 'it was not'} able to server-side render \`${compon
*/ */
NoClientEntrypoint: { NoClientEntrypoint: {
title: 'No client entrypoint specified in renderer.', title: 'No client entrypoint specified in renderer.',
code: 3008,
message: (componentName: string, clientDirective: string, rendererName: string) => message: (componentName: string, clientDirective: string, rendererName: string) =>
`\`${componentName}\` component has a \`client:${clientDirective}\` directive, but no client entrypoint was provided by \`${rendererName}\`.`, `\`${componentName}\` component has a \`client:${clientDirective}\` directive, but no client entrypoint was provided by \`${rendererName}\`.`,
hint: 'See https://docs.astro.build/en/reference/integrations-reference/#addrenderer-option for more information on how to configure your renderer.', hint: 'See https://docs.astro.build/en/reference/integrations-reference/#addrenderer-option for more information on how to configure your renderer.',
@ -211,7 +201,6 @@ but ${plural ? 'none were' : 'it was not'} able to server-side render \`${compon
*/ */
NoClientOnlyHint: { NoClientOnlyHint: {
title: 'Missing hint on client:only directive.', title: 'Missing hint on client:only directive.',
code: 3009,
message: (componentName: string) => message: (componentName: string) =>
`Unable to render \`${componentName}\`. When using the \`client:only\` hydration strategy, Astro needs a hint to use the correct renderer.`, `Unable to render \`${componentName}\`. When using the \`client:only\` hydration strategy, Astro needs a hint to use the correct renderer.`,
hint: (probableRenderers: string) => hint: (probableRenderers: string) =>
@ -238,7 +227,6 @@ but ${plural ? 'none were' : 'it was not'} able to server-side render \`${compon
*/ */
InvalidGetStaticPathParam: { InvalidGetStaticPathParam: {
title: 'Invalid value returned by a `getStaticPaths` path.', title: 'Invalid value returned by a `getStaticPaths` path.',
code: 3010,
message: (paramType) => message: (paramType) =>
`Invalid params given to \`getStaticPaths\` path. Expected an \`object\`, got \`${paramType}\``, `Invalid params given to \`getStaticPaths\` path. Expected an \`object\`, got \`${paramType}\``,
hint: 'See https://docs.astro.build/en/reference/api-reference/#getstaticpaths for more information on getStaticPaths.', hint: 'See https://docs.astro.build/en/reference/api-reference/#getstaticpaths for more information on getStaticPaths.',
@ -262,7 +250,6 @@ but ${plural ? 'none were' : 'it was not'} able to server-side render \`${compon
*/ */
InvalidGetStaticPathsReturn: { InvalidGetStaticPathsReturn: {
title: 'Invalid value returned by getStaticPaths.', title: 'Invalid value returned by getStaticPaths.',
code: 3011,
message: (returnType) => message: (returnType) =>
`Invalid type returned by \`getStaticPaths\`. Expected an \`array\`, got \`${returnType}\``, `Invalid type returned by \`getStaticPaths\`. Expected an \`array\`, got \`${returnType}\``,
hint: 'See https://docs.astro.build/en/reference/api-reference/#getstaticpaths for more information on getStaticPaths.', hint: 'See https://docs.astro.build/en/reference/api-reference/#getstaticpaths for more information on getStaticPaths.',
@ -276,7 +263,6 @@ but ${plural ? 'none were' : 'it was not'} able to server-side render \`${compon
*/ */
GetStaticPathsRemovedRSSHelper: { GetStaticPathsRemovedRSSHelper: {
title: 'getStaticPaths RSS helper is not available anymore.', title: 'getStaticPaths RSS helper is not available anymore.',
code: 3012,
message: message:
'The RSS helper has been removed from `getStaticPaths`. Try the new @astrojs/rss package instead.', 'The RSS helper has been removed from `getStaticPaths`. Try the new @astrojs/rss package instead.',
hint: 'See https://docs.astro.build/en/guides/rss/ for more information.', hint: 'See https://docs.astro.build/en/guides/rss/ for more information.',
@ -303,7 +289,6 @@ but ${plural ? 'none were' : 'it was not'} able to server-side render \`${compon
*/ */
GetStaticPathsExpectedParams: { GetStaticPathsExpectedParams: {
title: 'Missing params property on `getStaticPaths` route.', title: 'Missing params property on `getStaticPaths` route.',
code: 3013,
message: 'Missing or empty required `params` property on `getStaticPaths` route.', message: 'Missing or empty required `params` property on `getStaticPaths` route.',
hint: 'See https://docs.astro.build/en/reference/api-reference/#getstaticpaths for more information on getStaticPaths.', hint: 'See https://docs.astro.build/en/reference/api-reference/#getstaticpaths for more information on getStaticPaths.',
}, },
@ -343,7 +328,6 @@ but ${plural ? 'none were' : 'it was not'} able to server-side render \`${compon
*/ */
GetStaticPathsInvalidRouteParam: { GetStaticPathsInvalidRouteParam: {
title: 'Invalid value for `getStaticPaths` route parameter.', title: 'Invalid value for `getStaticPaths` route parameter.',
code: 3014,
message: (key: string, value: any, valueType: any) => message: (key: string, value: any, valueType: any) =>
`Invalid getStaticPaths route parameter for \`${key}\`. Expected undefined, a string or a number, received \`${valueType}\` (\`${value}\`)`, `Invalid getStaticPaths route parameter for \`${key}\`. Expected undefined, a string or a number, received \`${valueType}\` (\`${value}\`)`,
hint: 'See https://docs.astro.build/en/reference/api-reference/#getstaticpaths for more information on getStaticPaths.', hint: 'See https://docs.astro.build/en/reference/api-reference/#getstaticpaths for more information on getStaticPaths.',
@ -359,7 +343,6 @@ but ${plural ? 'none were' : 'it was not'} able to server-side render \`${compon
*/ */
GetStaticPathsRequired: { GetStaticPathsRequired: {
title: '`getStaticPaths()` function required for dynamic routes.', title: '`getStaticPaths()` function required for dynamic routes.',
code: 3015,
message: message:
'`getStaticPaths()` function is required for dynamic routes. Make sure that you `export` a `getStaticPaths` function from your dynamic route.', '`getStaticPaths()` function is required for dynamic routes. Make sure that you `export` a `getStaticPaths` function from your dynamic route.',
hint: `See https://docs.astro.build/en/core-concepts/routing/#dynamic-routes for more information on dynamic routes. hint: `See https://docs.astro.build/en/core-concepts/routing/#dynamic-routes for more information on dynamic routes.
@ -376,7 +359,6 @@ See https://docs.astro.build/en/guides/server-side-rendering/ for more informati
*/ */
ReservedSlotName: { ReservedSlotName: {
title: 'Invalid slot name.', title: 'Invalid slot name.',
code: 3016,
message: (slotName: string) => message: (slotName: string) =>
`Unable to create a slot named \`${slotName}\`. \`${slotName}\` is a reserved slot name. Please update the name of this slot.`, `Unable to create a slot named \`${slotName}\`. \`${slotName}\` is a reserved slot name. Please update the name of this slot.`,
}, },
@ -390,7 +372,6 @@ See https://docs.astro.build/en/guides/server-side-rendering/ for more informati
*/ */
NoAdapterInstalled: { NoAdapterInstalled: {
title: 'Cannot use Server-side Rendering without an adapter.', title: 'Cannot use Server-side Rendering without an adapter.',
code: 3017,
message: `Cannot use \`output: 'server'\` or \`output: 'hybrid'\` without an adapter. Please install and configure the appropriate server adapter for your final deployment.`, message: `Cannot use \`output: 'server'\` or \`output: 'hybrid'\` without an adapter. Please install and configure the appropriate server adapter for your final deployment.`,
hint: 'See https://docs.astro.build/en/guides/server-side-rendering/ for more information.', hint: 'See https://docs.astro.build/en/guides/server-side-rendering/ for more information.',
}, },
@ -401,7 +382,6 @@ See https://docs.astro.build/en/guides/server-side-rendering/ for more informati
*/ */
NoMatchingImport: { NoMatchingImport: {
title: 'No import found for component.', title: 'No import found for component.',
code: 3018,
message: (componentName: string) => message: (componentName: string) =>
`Could not render \`${componentName}\`. No matching import has been found for \`${componentName}\`.`, `Could not render \`${componentName}\`. No matching import has been found for \`${componentName}\`.`,
hint: 'Please make sure the component is properly imported.', hint: 'Please make sure the component is properly imported.',
@ -416,7 +396,6 @@ See https://docs.astro.build/en/guides/server-side-rendering/ for more informati
*/ */
InvalidPrerenderExport: { InvalidPrerenderExport: {
title: 'Invalid prerender export.', title: 'Invalid prerender export.',
code: 3019,
message: (prefix: string, suffix: string, isHydridOuput: boolean) => { message: (prefix: string, suffix: string, isHydridOuput: boolean) => {
const defaultExpectedValue = isHydridOuput ? 'false' : 'true'; const defaultExpectedValue = isHydridOuput ? 'false' : 'true';
let msg = `A \`prerender\` export has been detected, but its value cannot be statically analyzed.`; let msg = `A \`prerender\` export has been detected, but its value cannot be statically analyzed.`;
@ -437,7 +416,6 @@ See https://docs.astro.build/en/guides/server-side-rendering/ for more informati
*/ */
InvalidComponentArgs: { InvalidComponentArgs: {
title: 'Invalid component arguments.', title: 'Invalid component arguments.',
code: 3020,
message: (name: string) => `Invalid arguments passed to${name ? ` <${name}>` : ''} component.`, message: (name: string) => `Invalid arguments passed to${name ? ` <${name}>` : ''} component.`,
hint: 'Astro components cannot be rendered directly via function call, such as `Component()` or `{items.map(Component)}`.', hint: 'Astro components cannot be rendered directly via function call, such as `Component()` or `{items.map(Component)}`.',
}, },
@ -450,7 +428,6 @@ See https://docs.astro.build/en/guides/server-side-rendering/ for more informati
*/ */
PageNumberParamNotFound: { PageNumberParamNotFound: {
title: 'Page number param not found.', title: 'Page number param not found.',
code: 3021,
message: (paramName: string) => message: (paramName: string) =>
`[paginate()] page number param \`${paramName}\` not found in your filepath.`, `[paginate()] page number param \`${paramName}\` not found in your filepath.`,
hint: 'Rename your file to `[page].astro` or `[...page].astro`.', hint: 'Rename your file to `[page].astro` or `[...page].astro`.',
@ -468,7 +445,6 @@ See https://docs.astro.build/en/guides/server-side-rendering/ for more informati
*/ */
ImageMissingAlt: { ImageMissingAlt: {
title: 'Missing alt property.', title: 'Missing alt property.',
code: 3022,
message: 'The alt property is required.', message: 'The alt property is required.',
hint: "The `alt` property is important for the purpose of accessibility, without it users using screen readers or other assistive technologies won't be able to understand what your image is supposed to represent. See https://developer.mozilla.org/en-US/docs/Web/HTML/Element/img#attr-alt for more information.", hint: "The `alt` property is important for the purpose of accessibility, without it users using screen readers or other assistive technologies won't be able to understand what your image is supposed to represent. See https://developer.mozilla.org/en-US/docs/Web/HTML/Element/img#attr-alt for more information.",
}, },
@ -483,7 +459,6 @@ See https://docs.astro.build/en/guides/server-side-rendering/ for more informati
*/ */
InvalidImageService: { InvalidImageService: {
title: 'Error while loading image service.', title: 'Error while loading image service.',
code: 3023,
message: message:
'There was an error loading the configured image service. Please see the stack trace for more information.', 'There was an error loading the configured image service. Please see the stack trace for more information.',
}, },
@ -501,7 +476,6 @@ See https://docs.astro.build/en/guides/server-side-rendering/ for more informati
*/ */
MissingImageDimension: { MissingImageDimension: {
title: 'Missing image dimensions', title: 'Missing image dimensions',
code: 3024,
message: (missingDimension: 'width' | 'height' | 'both', imageURL: string) => message: (missingDimension: 'width' | 'height' | 'both', imageURL: string) =>
`Missing ${ `Missing ${
missingDimension === 'both' missingDimension === 'both'
@ -526,7 +500,6 @@ See https://docs.astro.build/en/guides/server-side-rendering/ for more informati
*/ */
UnsupportedImageFormat: { UnsupportedImageFormat: {
title: 'Unsupported image format', title: 'Unsupported image format',
code: 3025,
message: (format: string, imagePath: string, supportedFormats: readonly string[]) => message: (format: string, imagePath: string, supportedFormats: readonly string[]) =>
`Received unsupported format \`${format}\` from \`${imagePath}\`. Currently only ${supportedFormats.join( `Received unsupported format \`${format}\` from \`${imagePath}\`. Currently only ${supportedFormats.join(
', ' ', '
@ -545,7 +518,6 @@ See https://docs.astro.build/en/guides/server-side-rendering/ for more informati
*/ */
PrerenderDynamicEndpointPathCollide: { PrerenderDynamicEndpointPathCollide: {
title: 'Prerendered dynamic endpoint has path collision.', title: 'Prerendered dynamic endpoint has path collision.',
code: 3026,
message: (pathname: string) => message: (pathname: string) =>
`Could not render \`${pathname}\` with an \`undefined\` param as the generated path will collide during prerendering. Prevent passing \`undefined\` as \`params\` for the endpoint's \`getStaticPaths()\` function, or add an additional extension to the endpoint's filename.`, `Could not render \`${pathname}\` with an \`undefined\` param as the generated path will collide during prerendering. Prevent passing \`undefined\` as \`params\` for the endpoint's \`getStaticPaths()\` function, or add an additional extension to the endpoint's filename.`,
hint: (filename: string) => hint: (filename: string) =>
@ -572,7 +544,6 @@ See https://docs.astro.build/en/guides/server-side-rendering/ for more informati
*/ */
ExpectedImage: { ExpectedImage: {
title: 'Expected src to be an image.', title: 'Expected src to be an image.',
code: 3027,
message: (options: string) => message: (options: string) =>
`Expected \`src\` property to be either an ESM imported image or a string with the path of a remote image. Received \`${options}\`.`, `Expected \`src\` property to be either an ESM imported image or a string with the path of a remote image. Received \`${options}\`.`,
hint: 'This error can often happen because of a wrong path. Make sure the path to your image is correct.', hint: 'This error can often happen because of a wrong path. Make sure the path to your image is correct.',
@ -595,7 +566,6 @@ See https://docs.astro.build/en/guides/server-side-rendering/ for more informati
*/ */
ExpectedImageOptions: { ExpectedImageOptions: {
title: 'Expected image options.', title: 'Expected image options.',
code: 3028,
message: (options: string) => message: (options: string) =>
`Expected getImage() parameter to be an object. Received \`${options}\`.`, `Expected getImage() parameter to be an object. Received \`${options}\`.`,
}, },
@ -612,7 +582,6 @@ See https://docs.astro.build/en/guides/server-side-rendering/ for more informati
*/ */
MarkdownImageNotFound: { MarkdownImageNotFound: {
title: 'Image not found.', title: 'Image not found.',
code: 3029,
message: (imagePath: string, fullImagePath: string | undefined) => message: (imagePath: string, fullImagePath: string | undefined) =>
`Could not find requested image \`${imagePath}\`${ `Could not find requested image \`${imagePath}\`${
fullImagePath ? ` at \`${fullImagePath}\`.` : '.' fullImagePath ? ` at \`${fullImagePath}\`.` : '.'
@ -626,7 +595,6 @@ See https://docs.astro.build/en/guides/server-side-rendering/ for more informati
*/ */
ResponseSentError: { ResponseSentError: {
title: 'Unable to set response.', title: 'Unable to set response.',
code: 3030,
message: 'The response has already been sent to the browser and cannot be altered.', message: 'The response has already been sent to the browser and cannot be altered.',
}, },
@ -646,7 +614,6 @@ See https://docs.astro.build/en/guides/server-side-rendering/ for more informati
*/ */
MiddlewareNoDataOrNextCalled: { MiddlewareNoDataOrNextCalled: {
title: "The middleware didn't return a response or call `next`.", title: "The middleware didn't return a response or call `next`.",
code: 3031,
message: message:
'The middleware needs to either return a `Response` object or call the `next` function.', 'The middleware needs to either return a `Response` object or call the `next` function.',
}, },
@ -666,7 +633,6 @@ See https://docs.astro.build/en/guides/server-side-rendering/ for more informati
*/ */
MiddlewareNotAResponse: { MiddlewareNotAResponse: {
title: 'The middleware returned something that is not a `Response` object.', title: 'The middleware returned something that is not a `Response` object.',
code: 3032,
message: 'Any data returned from middleware must be a valid `Response` object.', message: 'Any data returned from middleware must be a valid `Response` object.',
}, },
@ -687,7 +653,6 @@ See https://docs.astro.build/en/guides/server-side-rendering/ for more informati
*/ */
LocalsNotAnObject: { LocalsNotAnObject: {
title: 'Value assigned to `locals` is not accepted.', title: 'Value assigned to `locals` is not accepted.',
code: 3033,
message: message:
'`locals` can only be assigned to an object. Other values like numbers, strings, etc. are not accepted.', '`locals` can only be assigned to an object. Other values like numbers, strings, etc. are not accepted.',
hint: 'If you tried to remove some information from the `locals` object, try to use `delete` or set the property to `undefined`.', hint: 'If you tried to remove some information from the `locals` object, try to use `delete` or set the property to `undefined`.',
@ -714,7 +679,6 @@ See https://docs.astro.build/en/guides/server-side-rendering/ for more informati
*/ */
LocalImageUsedWrongly: { LocalImageUsedWrongly: {
title: 'ESM imported images must be passed as-is.', title: 'ESM imported images must be passed as-is.',
code: 3034,
message: (imageFilePath: string) => message: (imageFilePath: string) =>
`\`Image\`'s and \`getImage\`'s \`src\` parameter must be an imported image or an URL, it cannot be a filepath. Received \`${imageFilePath}\`.`, `\`Image\`'s and \`getImage\`'s \`src\` parameter must be an imported image or an URL, it cannot be a filepath. Received \`${imageFilePath}\`.`,
}, },
@ -728,7 +692,6 @@ See https://docs.astro.build/en/guides/server-side-rendering/ for more informati
*/ */
AstroGlobUsedOutside: { AstroGlobUsedOutside: {
title: 'Astro.glob() used outside of an Astro file.', title: 'Astro.glob() used outside of an Astro file.',
code: 3035,
message: (globStr: string) => message: (globStr: string) =>
`\`Astro.glob(${globStr})\` can only be used in \`.astro\` files. \`import.meta.glob(${globStr})\` can be used instead to achieve a similar result.`, `\`Astro.glob(${globStr})\` can only be used in \`.astro\` files. \`import.meta.glob(${globStr})\` can be used instead to achieve a similar result.`,
hint: "See Vite's documentation on `import.meta.glob` for more information: https://vitejs.dev/guide/features.html#glob-import", hint: "See Vite's documentation on `import.meta.glob` for more information: https://vitejs.dev/guide/features.html#glob-import",
@ -743,7 +706,6 @@ See https://docs.astro.build/en/guides/server-side-rendering/ for more informati
*/ */
AstroGlobNoMatch: { AstroGlobNoMatch: {
title: 'Astro.glob() did not match any files.', title: 'Astro.glob() did not match any files.',
code: 3036,
message: (globStr: string) => message: (globStr: string) =>
`\`Astro.glob(${globStr})\` did not return any matching files. Check the pattern for typos.`, `\`Astro.glob(${globStr})\` did not return any matching files. Check the pattern for typos.`,
}, },
@ -756,7 +718,6 @@ See https://docs.astro.build/en/guides/server-side-rendering/ for more informati
*/ */
RedirectWithNoLocation: { RedirectWithNoLocation: {
title: 'A redirect must be given a location with the `Location` header.', title: 'A redirect must be given a location with the `Location` header.',
code: 3037,
}, },
/** /**
* @docs * @docs
@ -767,7 +728,6 @@ See https://docs.astro.build/en/guides/server-side-rendering/ for more informati
*/ */
InvalidDynamicRoute: { InvalidDynamicRoute: {
title: 'Invalid dynamic route.', title: 'Invalid dynamic route.',
code: 3038,
message: (route: string, invalidParam: string, received: string) => message: (route: string, invalidParam: string, received: string) =>
`The ${invalidParam} param for route ${route} is invalid. Received **${received}**.`, `The ${invalidParam} param for route ${route} is invalid. Received **${received}**.`,
}, },
@ -784,7 +744,6 @@ See https://docs.astro.build/en/guides/server-side-rendering/ for more informati
*/ */
UnknownViteError: { UnknownViteError: {
title: 'Unknown Vite Error.', title: 'Unknown Vite Error.',
code: 4000,
}, },
/** /**
* @docs * @docs
@ -797,7 +756,6 @@ See https://docs.astro.build/en/guides/server-side-rendering/ for more informati
*/ */
FailedToLoadModuleSSR: { FailedToLoadModuleSSR: {
title: 'Could not import file.', title: 'Could not import file.',
code: 4001,
message: (importName: string) => `Could not import \`${importName}\`.`, message: (importName: string) => `Could not import \`${importName}\`.`,
hint: 'This is often caused by a typo in the import path. Please make sure the file exists.', hint: 'This is often caused by a typo in the import path. Please make sure the file exists.',
}, },
@ -810,7 +768,6 @@ See https://docs.astro.build/en/guides/server-side-rendering/ for more informati
*/ */
InvalidGlob: { InvalidGlob: {
title: 'Invalid glob pattern.', title: 'Invalid glob pattern.',
code: 4002,
message: (globPattern: string) => message: (globPattern: string) =>
`Invalid glob pattern: \`${globPattern}\`. Glob patterns must start with './', '../' or '/'.`, `Invalid glob pattern: \`${globPattern}\`. Glob patterns must start with './', '../' or '/'.`,
hint: 'See https://docs.astro.build/en/guides/imports/#glob-patterns for more information on supported glob patterns.', hint: 'See https://docs.astro.build/en/guides/imports/#glob-patterns for more information on supported glob patterns.',
@ -822,7 +779,6 @@ See https://docs.astro.build/en/guides/server-side-rendering/ for more informati
*/ */
FailedToFindPageMapSSR: { FailedToFindPageMapSSR: {
title: "Astro couldn't find the correct page to render", title: "Astro couldn't find the correct page to render",
code: 4003,
message: message:
"Astro couldn't find the correct page to render, probably because it wasn't correctly mapped for SSR usage. This is an internal error. Please file an issue.", "Astro couldn't find the correct page to render, probably because it wasn't correctly mapped for SSR usage. This is an internal error. Please file an issue.",
}, },
@ -841,7 +797,6 @@ See https://docs.astro.build/en/guides/server-side-rendering/ for more informati
*/ */
UnknownCSSError: { UnknownCSSError: {
title: 'Unknown CSS Error.', title: 'Unknown CSS Error.',
code: 5000,
}, },
/** /**
* @docs * @docs
@ -854,7 +809,6 @@ See https://docs.astro.build/en/guides/server-side-rendering/ for more informati
*/ */
CSSSyntaxError: { CSSSyntaxError: {
title: 'CSS Syntax Error.', title: 'CSS Syntax Error.',
code: 5001,
}, },
/** /**
* @docs * @docs
@ -869,7 +823,6 @@ See https://docs.astro.build/en/guides/server-side-rendering/ for more informati
*/ */
UnknownMarkdownError: { UnknownMarkdownError: {
title: 'Unknown Markdown Error.', title: 'Unknown Markdown Error.',
code: 6000,
}, },
/** /**
* @docs * @docs
@ -884,7 +837,6 @@ See https://docs.astro.build/en/guides/server-side-rendering/ for more informati
*/ */
MarkdownFrontmatterParseError: { MarkdownFrontmatterParseError: {
title: 'Failed to parse Markdown frontmatter.', title: 'Failed to parse Markdown frontmatter.',
code: 6001,
}, },
/** /**
* @docs * @docs
@ -895,7 +847,6 @@ See https://docs.astro.build/en/guides/server-side-rendering/ for more informati
*/ */
InvalidFrontmatterInjectionError: { InvalidFrontmatterInjectionError: {
title: 'Invalid frontmatter injection.', title: 'Invalid frontmatter injection.',
code: 6003,
message: message:
'A remark or rehype plugin attempted to inject invalid frontmatter. Ensure "astro.frontmatter" is set to a valid JSON object that is not `null` or `undefined`.', 'A remark or rehype plugin attempted to inject invalid frontmatter. Ensure "astro.frontmatter" is set to a valid JSON object that is not `null` or `undefined`.',
hint: 'See the frontmatter injection docs https://docs.astro.build/en/guides/markdown-content/#modifying-frontmatter-programmatically for more information.', hint: 'See the frontmatter injection docs https://docs.astro.build/en/guides/markdown-content/#modifying-frontmatter-programmatically for more information.',
@ -909,7 +860,6 @@ See https://docs.astro.build/en/guides/server-side-rendering/ for more informati
*/ */
MdxIntegrationMissingError: { MdxIntegrationMissingError: {
title: 'MDX integration missing.', title: 'MDX integration missing.',
code: 6004,
message: (file: string) => message: (file: string) =>
`Unable to render ${file}. Ensure that the \`@astrojs/mdx\` integration is installed.`, `Unable to render ${file}. Ensure that the \`@astrojs/mdx\` integration is installed.`,
hint: 'See the MDX integration docs for installation and usage instructions: https://docs.astro.build/en/guides/integrations-guide/mdx/', hint: 'See the MDX integration docs for installation and usage instructions: https://docs.astro.build/en/guides/integrations-guide/mdx/',
@ -927,7 +877,6 @@ See https://docs.astro.build/en/guides/server-side-rendering/ for more informati
*/ */
UnknownConfigError: { UnknownConfigError: {
title: 'Unknown configuration error.', title: 'Unknown configuration error.',
code: 7000,
}, },
/** /**
* @docs * @docs
@ -938,7 +887,6 @@ See https://docs.astro.build/en/guides/server-side-rendering/ for more informati
*/ */
ConfigNotFound: { ConfigNotFound: {
title: 'Specified configuration file not found.', title: 'Specified configuration file not found.',
code: 7001,
message: (configFile: string) => message: (configFile: string) =>
`Unable to resolve \`--config "${configFile}"\`. Does the file exist?`, `Unable to resolve \`--config "${configFile}"\`. Does the file exist?`,
}, },
@ -951,7 +899,6 @@ See https://docs.astro.build/en/guides/server-side-rendering/ for more informati
*/ */
ConfigLegacyKey: { ConfigLegacyKey: {
title: 'Legacy configuration detected.', title: 'Legacy configuration detected.',
code: 7002,
message: (legacyConfigKey: string) => `Legacy configuration detected: \`${legacyConfigKey}\`.`, message: (legacyConfigKey: string) => `Legacy configuration detected: \`${legacyConfigKey}\`.`,
hint: 'Please update your configuration to the new format.\nSee https://astro.build/config for more information.', hint: 'Please update your configuration to the new format.\nSee https://astro.build/config for more information.',
}, },
@ -970,7 +917,6 @@ See https://docs.astro.build/en/guides/server-side-rendering/ for more informati
*/ */
UnknownCLIError: { UnknownCLIError: {
title: 'Unknown CLI Error.', title: 'Unknown CLI Error.',
code: 8000,
}, },
/** /**
* @docs * @docs
@ -981,7 +927,6 @@ See https://docs.astro.build/en/guides/server-side-rendering/ for more informati
*/ */
GenerateContentTypesError: { GenerateContentTypesError: {
title: 'Failed to generate content types.', title: 'Failed to generate content types.',
code: 8001,
message: (errorMessage: string) => message: (errorMessage: string) =>
`\`astro sync\` command failed to generate content collection types: ${errorMessage}`, `\`astro sync\` command failed to generate content collection types: ${errorMessage}`,
hint: 'Check your `src/content/config.*` file for typos.', hint: 'Check your `src/content/config.*` file for typos.',
@ -1002,7 +947,6 @@ See https://docs.astro.build/en/guides/server-side-rendering/ for more informati
*/ */
UnknownContentCollectionError: { UnknownContentCollectionError: {
title: 'Unknown Content Collection Error.', title: 'Unknown Content Collection Error.',
code: 9000,
}, },
/** /**
* @docs * @docs
@ -1019,7 +963,6 @@ See https://docs.astro.build/en/guides/server-side-rendering/ for more informati
*/ */
InvalidContentEntryFrontmatterError: { InvalidContentEntryFrontmatterError: {
title: 'Content entry frontmatter does not match schema.', title: 'Content entry frontmatter does not match schema.',
code: 9001,
message: (collection: string, entryId: string, error: ZodError) => { message: (collection: string, entryId: string, error: ZodError) => {
return [ return [
`**${String(collection)}${String( `**${String(collection)}${String(
@ -1040,7 +983,6 @@ See https://docs.astro.build/en/guides/server-side-rendering/ for more informati
*/ */
InvalidContentEntrySlugError: { InvalidContentEntrySlugError: {
title: 'Invalid content entry slug.', title: 'Invalid content entry slug.',
code: 9002,
message: (collection: string, entryId: string) => { message: (collection: string, entryId: string) => {
return `${String(collection)}${String( return `${String(collection)}${String(
entryId entryId
@ -1057,7 +999,6 @@ See https://docs.astro.build/en/guides/server-side-rendering/ for more informati
*/ */
ContentSchemaContainsSlugError: { ContentSchemaContainsSlugError: {
title: 'Content Schema should not contain `slug`.', title: 'Content Schema should not contain `slug`.',
code: 9003,
message: (collectionName: string) => message: (collectionName: string) =>
`A content collection schema should not contain \`slug\` since it is reserved for slug generation. Remove this from your ${collectionName} collection schema.`, `A content collection schema should not contain \`slug\` since it is reserved for slug generation. Remove this from your ${collectionName} collection schema.`,
hint: 'See https://docs.astro.build/en/guides/content-collections/ for more on the `slug` field.', hint: 'See https://docs.astro.build/en/guides/content-collections/ for more on the `slug` field.',
@ -1071,7 +1012,6 @@ See https://docs.astro.build/en/guides/server-side-rendering/ for more informati
*/ */
CollectionDoesNotExistError: { CollectionDoesNotExistError: {
title: 'Collection does not exist', title: 'Collection does not exist',
code: 9004,
message: (collectionName: string) => message: (collectionName: string) =>
`The collection **${collectionName}** does not exist. Ensure a collection directory with this name exists.`, `The collection **${collectionName}** does not exist. Ensure a collection directory with this name exists.`,
hint: 'See https://docs.astro.build/en/guides/content-collections/ for more on creating collections.', hint: 'See https://docs.astro.build/en/guides/content-collections/ for more on creating collections.',
@ -1086,7 +1026,6 @@ See https://docs.astro.build/en/guides/server-side-rendering/ for more informati
*/ */
MixedContentDataCollectionError: { MixedContentDataCollectionError: {
title: 'Content and data cannot be in same collection.', title: 'Content and data cannot be in same collection.',
code: 9005,
message: (collection: string) => { message: (collection: string) => {
return `**${collection}** contains a mix of content and data entries. All entries must be of the same type.`; return `**${collection}** contains a mix of content and data entries. All entries must be of the same type.`;
}, },
@ -1102,7 +1041,6 @@ See https://docs.astro.build/en/guides/server-side-rendering/ for more informati
*/ */
ContentCollectionTypeMismatchError: { ContentCollectionTypeMismatchError: {
title: 'Collection contains entries of a different type.', title: 'Collection contains entries of a different type.',
code: 9006,
message: (collection: string, expectedType: string, actualType: string) => { message: (collection: string, expectedType: string, actualType: string) => {
return `${collection} contains ${expectedType} entries, but is configured as a ${actualType} collection.`; return `${collection} contains ${expectedType} entries, but is configured as a ${actualType} collection.`;
}, },
@ -1115,7 +1053,6 @@ See https://docs.astro.build/en/guides/server-side-rendering/ for more informati
*/ */
DataCollectionEntryParseError: { DataCollectionEntryParseError: {
title: 'Data collection entry failed to parse.', title: 'Data collection entry failed to parse.',
code: 9007,
message: (entryId: string, errorMessage: string) => { message: (entryId: string, errorMessage: string) => {
return `**${entryId}** failed to parse: ${errorMessage}`; return `**${entryId}** failed to parse: ${errorMessage}`;
}, },
@ -1129,7 +1066,6 @@ See https://docs.astro.build/en/guides/server-side-rendering/ for more informati
*/ */
DuplicateContentEntrySlugError: { DuplicateContentEntrySlugError: {
title: 'Duplicate content entry slug.', title: 'Duplicate content entry slug.',
code: 9008,
message: (collection: string, slug: string) => { message: (collection: string, slug: string) => {
return `**${collection}** contains multiple entries with the same slug: \`${slug}\`. Slugs must be unique.`; return `**${collection}** contains multiple entries with the same slug: \`${slug}\`. Slugs must be unique.`;
}, },
@ -1144,7 +1080,6 @@ See https://docs.astro.build/en/guides/server-side-rendering/ for more informati
*/ */
UnsupportedConfigTransformError: { UnsupportedConfigTransformError: {
title: 'Unsupported transform in content config.', title: 'Unsupported transform in content config.',
code: 9008,
message: (parseError: string) => message: (parseError: string) =>
`\`transform()\` functions in your content config must return valid JSON, or data types compatible with the devalue library (including Dates, Maps, and Sets).\nFull error: ${parseError}`, `\`transform()\` functions in your content config must return valid JSON, or data types compatible with the devalue library (including Dates, Maps, and Sets).\nFull error: ${parseError}`,
hint: 'See the devalue library for all supported types: https://github.com/rich-harris/devalue', hint: 'See the devalue library for all supported types: https://github.com/rich-harris/devalue',
@ -1153,11 +1088,5 @@ See https://docs.astro.build/en/guides/server-side-rendering/ for more informati
// Generic catch-all - Only use this in extreme cases, like if there was a cosmic ray bit flip // Generic catch-all - Only use this in extreme cases, like if there was a cosmic ray bit flip
UnknownError: { UnknownError: {
title: 'Unknown Error.', title: 'Unknown Error.',
code: 99999,
}, },
} as const satisfies Record<string, ErrorData>; } as const satisfies Record<string, ErrorData>;
type ValueOf<T> = T[keyof T];
export type AstroErrorCodes = ValueOf<{
[T in keyof typeof AstroErrorData]: (typeof AstroErrorData)[T]['code'];
}>;

View file

@ -1,12 +1,7 @@
import type { DiagnosticMessage } from '@astrojs/compiler';
import type { AstroErrorCodes } from './errors-data.js';
import { codeFrame } from './printer.js'; import { codeFrame } from './printer.js';
import { getErrorDataByCode } from './utils.js'; import { getErrorDataByTitle } from './utils.js';
type DiagnosticCode = DiagnosticMessage['code'];
interface ErrorProperties { interface ErrorProperties {
code: AstroErrorCodes | DiagnosticCode;
title?: string; title?: string;
name?: string; name?: string;
message?: string; message?: string;
@ -35,10 +30,6 @@ export function isAstroError(e: unknown): e is AstroError {
} }
export class AstroError extends Error { export class AstroError extends Error {
// NOTE: If this property is named `code`, Rollup will use it to fill the `pluginCode` property downstream
// This cause issues since we expect `pluginCode` to be a string containing code
// @see https://github.com/rollup/rollup/blob/9a741639f69f204ded8ea404675f725b8d56adca/src/utils/error.ts#L725
public errorCode: AstroErrorCodes | DiagnosticCode;
public loc: ErrorLocation | undefined; public loc: ErrorLocation | undefined;
public title: string | undefined; public title: string | undefined;
public hint: string | undefined; public hint: string | undefined;
@ -49,16 +40,19 @@ export class AstroError extends Error {
constructor(props: ErrorProperties, ...params: any) { constructor(props: ErrorProperties, ...params: any) {
super(...params); super(...params);
const { code, name, title, message, stack, location, hint, frame } = props; const { name, title, message, stack, location, hint, frame } = props;
this.title = title;
this.errorCode = code;
if (name && name !== 'Error') { if (name && name !== 'Error') {
this.name = name; this.name = name;
} else { } else if (this.title) {
// If we don't have a name, let's generate one from the code const errorData = getErrorDataByTitle(this.title)?.name;
this.name = getErrorDataByCode(this.errorCode)?.name ?? 'UnknownError';
if (errorData) {
this.name = errorData;
}
} }
this.title = title;
if (message) this.message = message; if (message) this.message = message;
// Only set this if we actually have a stack passed, otherwise uses Error's // Only set this if we actually have a stack passed, otherwise uses Error's
this.stack = stack ? stack : this.stack; this.stack = stack ? stack : this.stack;
@ -67,10 +61,6 @@ export class AstroError extends Error {
this.frame = frame; this.frame = frame;
} }
public setErrorCode(errorCode: AstroErrorCodes) {
this.errorCode = errorCode;
}
public setLocation(location: ErrorLocation): void { public setLocation(location: ErrorLocation): void {
this.loc = location; this.loc = location;
} }
@ -99,7 +89,7 @@ export class AstroError extends Error {
export class CompilerError extends AstroError { export class CompilerError extends AstroError {
type: ErrorTypes = 'CompilerError'; type: ErrorTypes = 'CompilerError';
constructor(props: Omit<ErrorProperties, 'code'> & { code: DiagnosticCode }, ...params: any) { constructor(props: ErrorProperties, ...params: any) {
super(props, ...params); super(props, ...params);
this.name = 'CompilerError'; this.name = 'CompilerError';
@ -162,7 +152,6 @@ export interface ErrorWithMetadata {
type?: ErrorTypes; type?: ErrorTypes;
message: string; message: string;
stack: string; stack: string;
errorCode?: number;
hint?: string; hint?: string;
id?: string; id?: string;
frame?: string; frame?: string;

View file

@ -1,12 +1,12 @@
export type { ErrorLocation, ErrorWithMetadata } from './errors'; export type { ErrorLocation, ErrorWithMetadata } from './errors';
export { AstroErrorData, type AstroErrorCodes } from './errors-data.js'; export { AstroErrorData } from './errors-data.js';
export { export {
AggregateError, AggregateError,
AstroError, AstroError,
CompilerError,
CSSError, CSSError,
isAstroError, CompilerError,
MarkdownError, MarkdownError,
isAstroError,
} from './errors.js'; } from './errors.js';
export { codeFrame } from './printer.js'; export { codeFrame } from './printer.js';
export { createSafeError, positionAt } from './utils.js'; export { createSafeError, positionAt } from './utils.js';

View file

@ -1,10 +1,7 @@
import type { DiagnosticMessage } from '@astrojs/compiler';
import type { YAMLException } from 'js-yaml'; import type { YAMLException } from 'js-yaml';
import type { ErrorPayload as ViteErrorPayload } from 'vite'; import type { ErrorPayload as ViteErrorPayload } from 'vite';
import type { SSRError } from '../../@types/astro.js'; import type { SSRError } from '../../@types/astro.js';
import { AstroErrorData, type AstroErrorCodes, type ErrorData } from './errors-data.js'; import { AstroErrorData, type ErrorData } from './errors-data.js';
type DiagnosticCode = DiagnosticMessage['code'];
/** /**
* Get the line and character based on the offset * Get the line and character based on the offset
@ -109,8 +106,8 @@ export function normalizeLF(code: string) {
return code.replace(/\r\n|\r(?!\n)|\n/g, '\n'); return code.replace(/\r\n|\r(?!\n)|\n/g, '\n');
} }
export function getErrorDataByCode(code: AstroErrorCodes | DiagnosticCode) { export function getErrorDataByTitle(title: string) {
const entry = Object.entries(AstroErrorData).find((data) => data[1].code === code); const entry = Object.entries(AstroErrorData).find((data) => data[1].title === title);
if (entry) { if (entry) {
return { return {

View file

@ -1,11 +1,10 @@
import type { ZodError } from 'zod'; import type { ZodError } from 'zod';
import type { ErrorData } from '../core/errors/errors-data.js';
import { AstroError, AstroErrorData, type ErrorWithMetadata } from '../core/errors/index.js'; import { AstroError, AstroErrorData, type ErrorWithMetadata } from '../core/errors/index.js';
import { getErrorDataByCode } from '../core/errors/utils.js';
const EVENT_ERROR = 'ASTRO_CLI_ERROR'; const EVENT_ERROR = 'ASTRO_CLI_ERROR';
interface ErrorEventPayload { interface ErrorEventPayload {
code: number | undefined;
name: string; name: string;
isFatal: boolean; isFatal: boolean;
plugin?: string | undefined; plugin?: string | undefined;
@ -46,7 +45,6 @@ export function eventConfigError({
isFatal: boolean; isFatal: boolean;
}): { eventName: string; payload: ConfigErrorEventPayload }[] { }): { eventName: string; payload: ConfigErrorEventPayload }[] {
const payload: ConfigErrorEventPayload = { const payload: ConfigErrorEventPayload = {
code: AstroErrorData.UnknownConfigError.code,
name: 'ZodError', name: 'ZodError',
isFatal, isFatal,
isConfig: true, isConfig: true,
@ -66,10 +64,9 @@ export function eventError({
isFatal: boolean; isFatal: boolean;
}): { eventName: string; payload: ErrorEventPayload }[] { }): { eventName: string; payload: ErrorEventPayload }[] {
const errorData = const errorData =
AstroError.is(err) && err.errorCode ? getErrorDataByCode(err.errorCode)?.data : undefined; AstroError.is(err) && (AstroErrorData[err.name as keyof typeof AstroErrorData] as ErrorData);
const payload: ErrorEventPayload = { const payload: ErrorEventPayload = {
code: err.code || err.errorCode || AstroErrorData.UnknownError.code,
name: err.name, name: err.name,
plugin: err.plugin, plugin: err.plugin,
cliCommand: cmd, cliCommand: cmd,

View file

@ -27,7 +27,6 @@ function safeMatter(source: string, id: string) {
return matter(source); return matter(source);
} catch (err: any) { } catch (err: any) {
const markdownError = new MarkdownError({ const markdownError = new MarkdownError({
code: AstroErrorData.UnknownMarkdownError.code,
message: err.message, message: err.message,
stack: err.stack, stack: err.stack,
location: { location: {
@ -36,7 +35,6 @@ function safeMatter(source: string, id: string) {
}); });
if (err.name === 'YAMLException') { if (err.name === 'YAMLException') {
markdownError.setErrorCode(AstroErrorData.MarkdownFrontmatterParseError.code);
markdownError.setLocation({ markdownError.setLocation({
file: id, file: id,
line: err.mark.line, line: err.mark.line,

View file

@ -4,8 +4,8 @@ import { basename } from 'node:path';
import { Writable } from 'node:stream'; import { Writable } from 'node:stream';
import { removeDir } from '../dist/core/fs/index.js'; import { removeDir } from '../dist/core/fs/index.js';
import testAdapter from './test-adapter.js'; import testAdapter from './test-adapter.js';
import { loadFixture } from './test-utils.js';
import { testImageService } from './test-image-service.js'; import { testImageService } from './test-image-service.js';
import { loadFixture } from './test-utils.js';
describe('astro:image', () => { describe('astro:image', () => {
/** @type {import('./test-utils').Fixture} */ /** @type {import('./test-utils').Fixture} */
@ -118,7 +118,7 @@ describe('astro:image', () => {
expect(logs[0].message).to.contain('Received unsupported format'); expect(logs[0].message).to.contain('Received unsupported format');
}); });
it("errors when an ESM imported image's src is passed to Image/getImage instead of the full import ssss", async () => { it("errors when an ESM imported image's src is passed to Image/getImage instead of the full import", async () => {
logs.length = 0; logs.length = 0;
let res = await fixture.fetch('/error-image-src-passed'); let res = await fixture.fetch('/error-image-src-passed');
await res.text(); await res.text();

View file

@ -18,7 +18,7 @@ describe('Dynamic endpoint collision', () => {
}); });
it('throw error when dynamic endpoint has path collision', async () => { it('throw error when dynamic endpoint has path collision', async () => {
expect(errorMsg.errorCode).to.eq(3026); expect(errorMsg.name).to.eq('PrerenderDynamicEndpointPathCollide');
}); });
}); });

View file

@ -435,7 +435,6 @@ describe('Events', () => {
expect(event).to.deep.equal({ expect(event).to.deep.equal({
eventName: 'ASTRO_CLI_ERROR', eventName: 'ASTRO_CLI_ERROR',
payload: { payload: {
code: AstroErrorData.UnknownConfigError.code,
name: 'ZodError', name: 'ZodError',
isFatal: true, isFatal: true,
isConfig: true, isConfig: true,
@ -459,7 +458,6 @@ describe('Events', () => {
expect(event).to.deep.equal({ expect(event).to.deep.equal({
eventName: 'ASTRO_CLI_ERROR', eventName: 'ASTRO_CLI_ERROR',
payload: { payload: {
code: 1234,
plugin: 'TEST PLUGIN', plugin: 'TEST PLUGIN',
name: 'Error', name: 'Error',
isFatal: true, isFatal: true,
@ -485,7 +483,6 @@ describe('Events', () => {
anonymousMessageHint: anonymousMessageHint:
'`Astro.clientAddress` is not available in the `ADAPTER_NAME` adapter. File an issue with the adapter to add support.', '`Astro.clientAddress` is not available in the `ADAPTER_NAME` adapter. File an issue with the adapter to add support.',
cliCommand: 'COMMAND_NAME', cliCommand: 'COMMAND_NAME',
code: 3002,
isFatal: false, isFatal: false,
name: 'ClientAddressNotAvailable', name: 'ClientAddressNotAvailable',
plugin: undefined, plugin: undefined,
@ -502,7 +499,6 @@ describe('Events', () => {
expect(event).to.deep.equal({ expect(event).to.deep.equal({
eventName: 'ASTRO_CLI_ERROR', eventName: 'ASTRO_CLI_ERROR',
payload: { payload: {
code: AstroErrorData.UnknownError.code,
name: 'Error', name: 'Error',
plugin: undefined, plugin: undefined,
isFatal: false, isFatal: false,

View file

@ -14,7 +14,7 @@ describe('astro/src/core/cookies', () => {
cookies.set('foo', 'bar'); cookies.set('foo', 'bar');
expect(false).to.equal(true); expect(false).to.equal(true);
} catch (err) { } catch (err) {
expect(err.errorCode).to.equal(3030); expect(err.name).to.equal('ResponseSentError');
} }
}); });
}); });

View file

@ -1,10 +1,10 @@
import { expect } from 'chai'; import { expect } from 'chai';
import { createFsWithFallback } from '../test-utils.js'; import { fileURLToPath } from 'url';
import { defaultLogging } from '../../test-utils.js';
import { validateConfig } from '../../../dist/core/config/config.js'; import { validateConfig } from '../../../dist/core/config/config.js';
import { createSettings } from '../../../dist/core/config/index.js'; import { createSettings } from '../../../dist/core/config/index.js';
import { fileURLToPath } from 'url';
import { sync as _sync } from '../../../dist/core/sync/index.js'; import { sync as _sync } from '../../../dist/core/sync/index.js';
import { defaultLogging } from '../../test-utils.js';
import { createFsWithFallback } from '../test-utils.js';
const root = new URL('../../fixtures/content-mixed-errors/', import.meta.url); const root = new URL('../../fixtures/content-mixed-errors/', import.meta.url);
const logging = defaultLogging; const logging = defaultLogging;
@ -27,16 +27,16 @@ name: Ben
# Ben`, # Ben`,
'/src/content/authors/tony.json': `{ "name": "Tony" }`, '/src/content/authors/tony.json': `{ "name": "Tony" }`,
'/src/content/config.ts': ` '/src/content/config.ts': `
import { z, defineCollection } from 'astro:content'; import { z, defineCollection } from 'astro:content';
const authors = defineCollection({ const authors = defineCollection({
type: 'data', type: 'data',
schema: z.object({ schema: z.object({
name: z.string(), name: z.string(),
}), }),
}); });
export const collections = { authors };`, export const collections = { authors };`,
}, },
root root
@ -48,7 +48,6 @@ name: Ben
} catch (e) { } catch (e) {
expect(e).to.be.instanceOf(Error); expect(e).to.be.instanceOf(Error);
expect(e.type).to.equal('AstroError'); expect(e.type).to.equal('AstroError');
expect(e.errorCode).to.equal(9005);
expect(e.message).to.include('authors'); expect(e.message).to.include('authors');
} }
}); });
@ -63,16 +62,16 @@ title: Post
# Post`, # Post`,
'/src/content/blog/post.yaml': `title: YAML Post`, '/src/content/blog/post.yaml': `title: YAML Post`,
'/src/content/config.ts': ` '/src/content/config.ts': `
import { z, defineCollection } from 'astro:content'; import { z, defineCollection } from 'astro:content';
const blog = defineCollection({ const blog = defineCollection({
type: 'content', type: 'content',
schema: z.object({ schema: z.object({
title: z.string(), title: z.string(),
}), }),
}); });
export const collections = { blog };`, export const collections = { blog };`,
}, },
root root
@ -84,7 +83,7 @@ title: Post
} catch (e) { } catch (e) {
expect(e).to.be.instanceOf(Error); expect(e).to.be.instanceOf(Error);
expect(e.type).to.equal('AstroError'); expect(e.type).to.equal('AstroError');
expect(e.errorCode).to.equal(9005);
expect(e.message).to.include('blog'); expect(e.message).to.include('blog');
} }
}); });
@ -94,16 +93,16 @@ title: Post
{ {
'/src/content/banners/welcome.json': `{ "src": "/example", "alt": "Welcome" }`, '/src/content/banners/welcome.json': `{ "src": "/example", "alt": "Welcome" }`,
'/src/content/config.ts': ` '/src/content/config.ts': `
import { z, defineCollection } from 'astro:content'; import { z, defineCollection } from 'astro:content';
const banners = defineCollection({ const banners = defineCollection({
schema: z.object({ schema: z.object({
src: z.string(), src: z.string(),
alt: z.string(), alt: z.string(),
}), }),
}); });
export const collections = { banners };`, export const collections = { banners };`,
}, },
root root
@ -115,7 +114,6 @@ title: Post
} catch (e) { } catch (e) {
expect(e).to.be.instanceOf(Error); expect(e).to.be.instanceOf(Error);
expect(e.type).to.equal('AstroError'); expect(e.type).to.equal('AstroError');
expect(e.errorCode).to.equal(9006);
expect(e.hint).to.include("Try adding `type: 'data'`"); expect(e.hint).to.include("Try adding `type: 'data'`");
} }
}); });
@ -127,14 +125,14 @@ title: Post
'/src/content/i18n/_placeholder.txt': 'Need content here', '/src/content/i18n/_placeholder.txt': 'Need content here',
'/src/content/config.ts': ` '/src/content/config.ts': `
import { z, defineCollection } from 'astro:content'; import { z, defineCollection } from 'astro:content';
const i18n = defineCollection({ const i18n = defineCollection({
type: 'data', type: 'data',
schema: z.object({ schema: z.object({
greeting: z.string(), greeting: z.string(),
}), }),
}); });
export const collections = { i18n };`, export const collections = { i18n };`,
}, },
root root

View file

@ -52,7 +52,6 @@ describe('astro scan', () => {
const result = await scan(`export let prerender = true;`, '/src/components/index.astro'); const result = await scan(`export let prerender = true;`, '/src/components/index.astro');
expect(false).to.be.true; expect(false).to.be.true;
} catch (e) { } catch (e) {
expect(e.errorCode).to.equal(3019);
expect(e.message).to.contain( expect(e.message).to.contain(
`A \`prerender\` export has been detected, but its value cannot be statically analyzed.` `A \`prerender\` export has been detected, but its value cannot be statically analyzed.`
); );
@ -64,7 +63,6 @@ describe('astro scan', () => {
const result = await scan(`export var prerender = true;`, '/src/components/index.astro'); const result = await scan(`export var prerender = true;`, '/src/components/index.astro');
expect(false).to.be.true; expect(false).to.be.true;
} catch (e) { } catch (e) {
expect(e.errorCode).to.equal(3019);
expect(e.message).to.contain( expect(e.message).to.contain(
`A \`prerender\` export has been detected, but its value cannot be statically analyzed.` `A \`prerender\` export has been detected, but its value cannot be statically analyzed.`
); );
@ -76,7 +74,6 @@ describe('astro scan', () => {
const result = await scan(`export const prerender = !!value;`, '/src/components/index.astro'); const result = await scan(`export const prerender = !!value;`, '/src/components/index.astro');
expect(false).to.be.true; expect(false).to.be.true;
} catch (e) { } catch (e) {
expect(e.errorCode).to.equal(3019);
expect(e.message).to.contain( expect(e.message).to.contain(
`A \`prerender\` export has been detected, but its value cannot be statically analyzed.` `A \`prerender\` export has been detected, but its value cannot be statically analyzed.`
); );
@ -88,7 +85,6 @@ describe('astro scan', () => {
const result = await scan(`export const prerender = value;`, '/src/components/index.astro'); const result = await scan(`export const prerender = value;`, '/src/components/index.astro');
expect(false).to.be.true; expect(false).to.be.true;
} catch (e) { } catch (e) {
expect(e.errorCode).to.equal(3019);
expect(e.message).to.contain( expect(e.message).to.contain(
`A \`prerender\` export has been detected, but its value cannot be statically analyzed.` `A \`prerender\` export has been detected, but its value cannot be statically analyzed.`
); );
@ -103,7 +99,6 @@ describe('astro scan', () => {
); );
expect(false).to.be.true; expect(false).to.be.true;
} catch (e) { } catch (e) {
expect(e.errorCode).to.equal(3019);
expect(e.message).to.contain( expect(e.message).to.contain(
`A \`prerender\` export has been detected, but its value cannot be statically analyzed.` `A \`prerender\` export has been detected, but its value cannot be statically analyzed.`
); );
@ -118,7 +113,6 @@ describe('astro scan', () => {
); );
expect(false).to.be.true; expect(false).to.be.true;
} catch (e) { } catch (e) {
expect(e.errorCode).to.equal(3019);
expect(e.message).to.contain( expect(e.message).to.contain(
`A \`prerender\` export has been detected, but its value cannot be statically analyzed.` `A \`prerender\` export has been detected, but its value cannot be statically analyzed.`
); );

View file

@ -29,7 +29,6 @@ export function parseFrontmatter(fileContents: string, filePath: string) {
* @see 'astro/src/core/errors/errors.ts' * @see 'astro/src/core/errors/errors.ts'
*/ */
export class MarkdocError extends Error { export class MarkdocError extends Error {
public errorCode: number;
public loc: ErrorLocation | undefined; public loc: ErrorLocation | undefined;
public title: string | undefined; public title: string | undefined;
public hint: string | undefined; public hint: string | undefined;
@ -40,20 +39,8 @@ export class MarkdocError extends Error {
constructor(props: ErrorProperties, ...params: any) { constructor(props: ErrorProperties, ...params: any) {
super(...params); super(...params);
const { const { name, title = 'MarkdocError', message, stack, location, hint, frame } = props;
// Use default code for unknown errors in Astro core
// We don't have a best practice for integration error codes yet
code = 99999,
name,
title = 'MarkdocError',
message,
stack,
location,
hint,
frame,
} = props;
this.errorCode = code;
this.title = title; this.title = title;
if (message) this.message = message; if (message) this.message = message;
// Only set this if we actually have a stack passed, otherwise uses Error's // Only set this if we actually have a stack passed, otherwise uses Error's