{"record":{"id":"582f21061784476c","repo":"hasura/graphql-engine","slug":"fragment-cycle-detected-through-0","errorCode":null,"errorMessage":"fragment cycle detected through: {0:?}","messagePattern":"fragment cycle detected through: (.+?)","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"v3/crates/graphql/lang-graphql/src/validation/error.rs","lineNumber":9,"sourceCode":"use thiserror::Error;\n\nuse crate::ast::{common as ast, spanning};\n\npub type Result<T> = core::result::Result<T, Error>;\n\n#[derive(Error, Debug, Clone)]\npub enum Error {\n    #[error(\"fragment cycle detected through: {0:?}\")]\n    CycleDetected(Vec<ast::Name>),\n    // TODO, this error isn't thrown yet\n    #[error(\"unused fragment: {0}\")]\n    FragmentNotUsed(ast::Name),\n    #[error(\"fragment not defined in the document: {0}\")]\n    UnknownFragment(ast::Name),\n    #[error(\"{} is defined on a non-composite type: {type_name}\", match fragment_name { None => \"inline fragment\".to_owned(), Some(fragment_name) => format!(\"fragment {fragment_name}\")})]\n    FragmentOnNonCompositeType {\n        fragment_name: Option<ast::Name>,\n        type_name: ast::TypeName,\n    },\n    #[error(\"fragment of type {fragment_type} cannot be spread on type {selection_type}\")]\n    FragmentCannotBeSpread {\n        selection_type: ast::TypeName,\n        fragment_type: ast::TypeName,\n    },\n    // TODO, this error isn't thrown yet\n    #[error(","sourceCodeStart":1,"sourceCodeEnd":27,"githubUrl":"https://github.com/hasura/graphql-engine/blob/724551b9ae87845594ef0408cff0e50eb6c90dc5/v3/crates/graphql/lang-graphql/src/validation/error.rs#L1-L27","documentation":"Query validation error: fragment spreads form a cycle (fragment A spreads B which spreads A, directly or transitively). The cycle path is reported as a list of fragment names. Note: an adjacent unused-fragment error exists in the same enum but is not yet thrown.","triggerScenarios":"Running document validation on an executable document whose fragment definitions reference each other, e.g. fragment A on T { ...B } fragment B on T { ...A }.","commonSituations":"Refactoring fragments that end up referencing each other, codegen or tooling that assembles fragments automatically and creates mutual inclusion, large query documents where the cycle spans many fragments.","solutions":["Inspect the reported cycle path and break it by removing one spread","Extract the shared fields into a third fragment both include instead of referencing each other","Add a fragment-dependency check/lint in CI for generated documents"],"exampleFix":"# before\nfragment A on User { name ...B }\nfragment B on User { email ...A }\n# after\nfragment A on User { name ...Shared }\nfragment B on User { email ...Shared }\nfragment Shared on User { id }","handlingStrategy":"validation","validationCode":"fn has_fragment_cycle(spreads: &HashMap<Name, Vec<Name>>) -> Option<Vec<Name>> {\n    // DFS from each fragment; return path when a node repeats\n    ...\n}","typeGuard":null,"tryCatchPattern":"Run the crate's validation pass on the document before execution and handle Error::CycleDetected(path) by reporting the fragment chain to the client/tooling.","preventionTips":["Lint fragment dependencies for cycles in CI","Keep shared fields in leaf fragments that spread nothing"],"tags":["graphql","validation","fragments","cycle"],"backgroundTag":"graphql-fragment-cycle","analyzedSha":"724551b9ae87845594ef0408cff0e50eb6c90dc5","analyzedAt":"2026-08-28T07:32:55.105Z","schemaVersion":2},"datasetVersion":"2026-08-28T11:17:15.048Z"}