withastro/astro · error · AstroError
UnsupportedConfigTransformError
UnsupportedConfigTransformError
Error message
`transform()` functions in your content config must return valid JSON, or data types compatible with the devalue library (including Dates, Maps, and Sets).
Full error: ${parseError} What it means
Collection entries are serialized with devalue so they can be stored in the data store and re-hydrated inside generated modules. A transform() function in your loader config must return JSON-compatible values (plus devalue-supported types like Date, Map, Set). When devalue's stringify encounters something it cannot handle — a function, symbol, class instance, or undefined inside an array — the error is wrapped as UnsupportedConfigTransformError with the parse error attached.
Solutions
- Map class instances to plain objects and strip functions before returning from transform().
- Convert wrapped types to primitives or built-ins: Moment to Date, Decimal to string, URL is supported natively.
- Add a unit test that runs devalue.stringify() over your transform output (see validation below).
Example fix
// before
loader: {
async load() {},
transform(entry) {
return { ...entry, published: new Moment(entry.date), href: (slug) => `/posts/${slug}` };
},
}
// after
loader: {
async load() {},
transform(entry) {
return { ...entry, published: new Date(entry.date) };
},
} Defensive patterns
Strategy: validation
Validate before calling
// Unit-test transform output with the same serializer Astro uses
import { stringify } from 'devalue';
test('loader transform output is serializable', () => {
for (const entry of sampleEntries) {
expect(() => stringify(myTransform(entry))).not.toThrow();
}
}); Type guard
const isPlainSerializable = (v: unknown): boolean => v === null || ['string', 'number', 'boolean'].includes(typeof v) || v instanceof Date || v instanceof Map || v instanceof Set || (Array.isArray(v) && v.every(isPlainSerializable)) || (typeof v === 'object' && Object.values(v).every(isPlainSerializable));
Prevention
- Return plain objects from transform(); convert class instances and wrapper types explicitly.
- Never attach functions to transformed data.
- Cover transforms with the devalue stringify test shown above in CI.
When it happens
Trigger: A transform() returning functions (href: (slug) => ...), symbols, class or model instances, Moment/Luxon wrappers, or undefined stored in arrays; cyclic structures.
Common situations: Returning ORM entities or rich objects from a loader transform; leaving helper functions attached to data; porting code that relied on structuredClone or JSON.stringify semantics that silently dropped functions.
Related errors
- PluginContentImportsError
- ActionsReturnedInvalidDataError
- Collection loader for
- Live content collections must be defined in…
- A content collection is defined with legacy features (e.g…
AI-assisted analysis of withastro/astro@e294953aa8 (2026-08-18).
Data as JSON: /api/errors/35d38ff99b58edf0.
Report an issue: GitHub.
Appendix: source
Thrown at packages/astro/src/content/vite-plugin-content-imports.ts:435
/** Stringify entry `data` at build time to be used as a Vite module */
function stringifyEntryData(data: Record<string, any>, isSSR: boolean): string {
try {
return devalue.uneval(data, (value) => {
// Add support for URL objects
if (value instanceof URL) {
return `new URL(${JSON.stringify(value.href)})`;
}
// For Astro assets, add a proxy to track references
if (typeof value === 'object' && 'ASTRO_ASSET' in value) {
const { ASTRO_ASSET, ...asset } = value;
asset.fsPath = ASTRO_ASSET;
return getProxyCode(asset, isSSR);
}
});
} catch (e) {
if (e instanceof Error) {
throw new AstroError({
...AstroErrorData.UnsupportedConfigTransformError,
message: AstroErrorData.UnsupportedConfigTransformError.message(e.message),
stack: e.stack,
});
} else {
throw new AstroError({
name: 'PluginContentImportsError',
message: 'Unexpected error processing content collection data.',
});
}
}
}
View on GitHub (pinned to e294953aa8)