{"record":{"id":"1b414851aff5157d","repo":"withastro/astro","slug":"invalid-transition-name-transitionname","errorCode":null,"errorMessage":"Invalid transition name {${transitionName}}","messagePattern":"Invalid transition name (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/astro/src/runtime/server/transition.ts","lineNumber":95,"sourceCode":"\t\t\t\tcodepoint < 0x80\n\t\t\t\t\t? codepoint === 95\n\t\t\t\t\t\t? '__'\n\t\t\t\t\t\t: (reEncodeValidChars[codepoint] ?? '_' + codepoint.toString(16).padStart(2, '0'))\n\t\t\t\t\t: String.fromCodePoint(codepoint);\n\t\t}\n\t}\n\t// Digits and minus sign at the beginning of the string are special, so we simply prepend an underscore\n\treturn reEncodeInValidStart[result.codePointAt(0) ?? 0] ? '_' + result : result;\n}\n\nexport function renderTransition(\n\tresult: SSRResult,\n\thash: string,\n\tanimationName: TransitionAnimationValue | undefined,\n\ttransitionName: string,\n) {\n\tif (typeof (transitionName ?? '') !== 'string') {\n\t\tthrow new Error(`Invalid transition name {${transitionName}}`);\n\t}\n\t// Default to `fade` (similar to `initial`, but snappier)\n\tif (!animationName) animationName = 'fade';\n\tconst scope = createTransitionScope(result, hash);\n\tconst name = transitionName ? cssesc(reEncode(transitionName), { isIdentifier: true }) : scope;\n\tconst sheet = new ViewTransitionStyleSheet(scope, name);\n\n\tconst animations = getAnimations(animationName);\n\tif (animations) {\n\t\taddPairs(animations, sheet);\n\t} else if (animationName === 'none') {\n\t\tsheet.addFallback('old', 'animation: none; mix-blend-mode: normal;');\n\t\tsheet.addModern('old', 'animation: none; opacity: 0; mix-blend-mode: normal;');\n\t\tsheet.addAnimationRaw('new', 'animation: none; mix-blend-mode: normal;');\n\t\tsheet.addModern('group', 'animation: none');\n\t}\n\n\tconst css = escapeStyleText(sheet.toString());","sourceCodeStart":77,"sourceCodeEnd":113,"githubUrl":"https://github.com/withastro/astro/blob/52e6c34790cc8ac4e69e6135ace06049867e5c4a/packages/astro/src/runtime/server/transition.ts#L77-L113","documentation":"Every element using transition:animate / transition:name goes through renderTransition, which generates the view-transition-name CSS for View Transitions. The name must be a string; null and undefined fall back to an auto-generated scope, but any other non-string value (number, boolean, object, symbol) throws this error. Strings that merely look odd (leading digits, spaces) are fine — Astro re-encodes them into valid identifiers.","triggerScenarios":"<div transition:name={42}>; transition:name={product.id} where the id is a number from the database or Astro.params; transition:name={{ slug: 'hero' }} passing an object by mistake; a name variable sourced from CMS data typed as anything but string.","commonSituations":"Dynamic transition names built from numeric IDs used without String(); passing a props object instead of one of its fields; refactors changing a name's type from string to number.","solutions":["Coerce the value to a string: transition:name={String(product.id)}","Fix the data source to produce strings (serialize at the data boundary in frontmatter)","If the element should not participate in view transitions, remove the transition:name / transition:animate directive"],"exampleFix":"<!-- before -->\n<div transition:name={product.id} transition:animate=\"slide\">\n\n<!-- after -->\n<div transition:name={String(product.id)} transition:animate=\"slide\">","handlingStrategy":"type-guard","validationCode":"---\nconst rawName = product.id; // number from the database\nconst name = isValidTransitionName(rawName) ? rawName : String(rawName);\n---\n<div transition:name={name}>","typeGuard":"const isValidTransitionName = (v: unknown): v is string | null | undefined =>\n\tv == null || typeof v === 'string';","tryCatchPattern":null,"preventionTips":["Always derive transition names from strings — wrap numeric ids with String() at the source","Type the variable you pass to transition:name as string in frontmatter","Remember null/undefined are safe (auto-generated scope); everything non-string is not"],"tags":["view-transitions","transition-name","type-error"],"backgroundTag":"invalid-view-transition-name","analyzedSha":"52e6c34790cc8ac4e69e6135ace06049867e5c4a","analyzedAt":"2026-08-18T18:48:03.901Z","contentChangedAt":"2026-08-18T18:48:03.901Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}