{"record":{"id":"57cb1e1a718cefc6","repo":"nolimits4web/swiper","slug":"swiper-loop-warning-loop-mode-is-not-compatible-w","errorCode":null,"errorMessage":"Swiper Loop Warning: Loop mode is not compatible with grid.fill = `row`","messagePattern":"Swiper Loop Warning: Loop mode is not compatible with grid\\.fill = `row`","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"src/core/loop/loopFix.ts","lineNumber":96,"sourceCode":"    ? Math.max(slidesPerGroup, Math.ceil(slidesPerView / 2))\n    : slidesPerGroup;\n\n  if (loopedSlides % slidesPerGroup !== 0) {\n    loopedSlides += slidesPerGroup - (loopedSlides % slidesPerGroup);\n  }\n  loopedSlides += params.loopAdditionalSlides!;\n  swiper.loopedSlides = loopedSlides;\n  const gridEnabled = swiper.grid && params.grid && params.grid.rows! > 1;\n\n  if (\n    slides.length < slidesPerView + loopedSlides ||\n    (swiper.params.effect === 'cards' && slides.length < slidesPerView + loopedSlides * 2)\n  ) {\n    showWarning(\n      'Swiper Loop Warning: The number of slides is not enough for loop mode, it will be disabled or not function properly. You need to add more slides (or make duplicates) or lower the values of slidesPerView and slidesPerGroup parameters',\n    );\n  } else if (gridEnabled && params.grid!.fill === 'row') {\n    showWarning('Swiper Loop Warning: Loop mode is not compatible with grid.fill = `row`');\n  }\n\n  const prependSlidesIndexes: number[] = [];\n  const appendSlidesIndexes: number[] = [];\n\n  const cols = gridEnabled ? Math.ceil(slides.length / params.grid!.rows!) : slides.length;\n\n  const isInitialOverflow =\n    initial && cols - (initialSlide as number) < slidesPerView && !bothDirections;\n\n  let activeIndex = isInitialOverflow ? (initialSlide as number) : swiper.activeIndex;\n\n  if (typeof activeSlideIndex === 'undefined') {\n    activeSlideIndex = swiper.getSlideIndex(\n      slides.find((el) => el.classList.contains(params.slideActiveClass!))!,\n    );\n  } else {\n    activeIndex = activeSlideIndex;","sourceCodeStart":78,"sourceCodeEnd":114,"githubUrl":"https://github.com/nolimits4web/swiper/blob/6138c2a6857d17fe097149dd3b975b2387d0b2dc/src/core/loop/loopFix.ts#L78-L114","documentation":"Emitted by loopFix in the else-if at src/core/loop/loopFix.ts:95-96 when grid is enabled (grid.rows > 1), grid.fill === 'row', and the slide-count guard for error [3] did NOT fire (it is an else-if). Loop mode clones and repositions slides by index, but grid.fill:'row' lays slides out row-major across columns; the two layouts conflict and Swiper explicitly does not support this combination. Because it is gated behind the else-if, this warning appears only when there ARE enough slides, so a valid-looking config can still warn here.","triggerScenarios":"{ loop:true, grid:{ rows:3, fill:'row' } } with a slide count large enough to pass the slidesPerView + loopedSlides minimum (loopFix.ts:88-91), so execution reaches the else-if at line 95. Any loop + multi-row grid with fill:'row' triggers it regardless of slide count, as long as the count minimum is satisfied.","commonSituations":"Wanting a multi-row looping carousel and copying a grid.fill:'row' config; reusing a grid layout preset inside a looping slider; version upgrades where grid fill semantics or the loop compatibility check changed; configs assembled from unrelated examples.","solutions":["Change grid.fill to 'column' (the default), which is the only fill mode compatible with loop.","If you must keep grid.fill:'row', disable loop:true.","Drop the grid module entirely if seamless loop is the priority.","Validate the combination at config-build time (see defense) so this never reaches loopFix."],"exampleFix":"// before -- loop + grid.fill 'row' -> warning at loopFix.ts:96\nnew Swiper(el, { loop: true, grid: { rows: 3, fill: 'row' } });\n// after -- use the loop-compatible fill, or disable loop\nnew Swiper(el, { loop: true, grid: { rows: 3, fill: 'column' } }); // supported\n// or: new Swiper(el, { grid: { rows: 3, fill: 'row' } }); // no loop","handlingStrategy":"validation","validationCode":"function assertLoopGridCompatible(p: { loop?: boolean; grid?: { rows?: number; fill?: 'row' | 'column' } }): void {\n  const rows = p.grid?.rows ?? 1;\n  if (p.loop && rows > 1 && p.grid?.fill === 'row') {\n    throw new Error('Swiper loop is incompatible with grid.fill=\"row\"; use grid.fill=\"column\" or disable loop.');\n  }\n}\nassertLoopGridCompatible(params); // run before `new Swiper(el, params)`","typeGuard":"function isLoopGridConfigValid(p: { loop?: boolean; grid?: { rows?: number; fill?: 'row' | 'column' } }): boolean {\n  return !(Boolean(p.loop) && (p.grid?.rows ?? 1) > 1 && p.grid?.fill === 'row');\n}","tryCatchPattern":null,"preventionTips":["Never combine loop:true with grid.fill:'row'; use grid.fill:'column' (the default) when looping.","Add a config-build assertion so the bad combination fails fast instead of warning at runtime.","If multi-row row-fill layout is required, disable loop and accept a finite carousel.","Document the grid.fill choice alongside any loop config so reviewers catch the mismatch."],"tags":["loop","grid","fill-row","config","compatibility"],"backgroundTag":null,"analyzedSha":"6138c2a6857d17fe097149dd3b975b2387d0b2dc","analyzedAt":"2026-08-12T21:16:10.868Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}