Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -272,7 +272,7 @@ private Imp modifyImp(Imp imp, PubmaticBidderImpExt impExt, String displayManage
final ObjectNode newExt = makeKeywords(impExt);

final Imp.ImpBuilder impBuilder = imp.toBuilder()
.banner(banner != null ? assignSizesIfMissing(banner) : null)
.banner(banner != null ? fillBannerSizeFromFormat(banner) : null)
.audio(null)
.bidfloor(resolveBidFloor(impExtBidder.getKadfloor(), imp.getBidfloor()))
.displaymanager(StringUtils.firstNonBlank(imp.getDisplaymanager(), displayManager))
Expand All @@ -281,12 +281,24 @@ private Imp modifyImp(Imp imp, PubmaticBidderImpExt impExt, String displayManage

enrichWithAdSlotParameters(impBuilder, impExtBidder.getAdSlot(), banner);

return impBuilder.build();
final Imp result = impBuilder.build();
final Banner resultBanner = result.getBanner();
// Per OpenRTB 2.6 spec, banner sizes are optional for interstitial impressions.
final boolean isInterstitial = Objects.equals(result.getInstl(), 1);
if (resultBanner != null && (resultBanner.getW() == null || resultBanner.getH() == null) && !isInterstitial) {
throw new PreBidException("No sizes provided for Banner");
}

return result;
Comment on lines +284 to +292

@osulzhenko osulzhenko Oct 13, 2026 •

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Aditya-9-6 I doubt this check is needed in PBS-Java. It replicates ImpValidator.validateBanner, so imps with invalid values will be dropped before reaching makeHttpRequests. PBS-Go might have something similar in request_validator_banner.go

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Confirmed: ImpValidator.validateBanner rejects the w=300, h=null, format=[] case for non-interstitial impressions before the adapter runs. My earlier example tested the adapter directly, so I withdraw it as a reason to add this guard.

}

private static Banner assignSizesIfMissing(Banner banner) {
private static Banner fillBannerSizeFromFormat(Banner banner) {
final List<Format> format = banner.getFormat();
if ((banner.getW() != null && banner.getH() != null) || CollectionUtils.isEmpty(format)) {
if (banner.getW() != null && banner.getH() != null) {
return banner;
}

if (CollectionUtils.isEmpty(format)) {
return banner;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -587,6 +587,83 @@ public void makeHttpRequestsShouldSetBannerWidthAndHeightFromFormatIfMissedOrigi
.containsExactly(100);
}

@Test
public void makeHttpRequestsShouldReturnErrorIfBannerHasNoSizesAndNoFormat() {
// given - non-interstitial banner with no W/H and no format: should error
final BidRequest bidRequest = givenBidRequest(
impBuilder -> impBuilder.banner(Banner.builder().build()),
extImpPubmaticBuilder -> extImpPubmaticBuilder.adSlot("slot"));

// when
final Result<List<HttpRequest<BidRequest>>> result = target.makeHttpRequests(bidRequest);

// then
assertThat(result.getErrors())
.containsExactly(BidderError.badInput("No sizes provided for Banner"));
assertThat(result.getValue()).isEmpty();
}

@Test
public void makeHttpRequestsShouldReturnErrorIfBannerHasOnlyOneDimensionAndNoFormat() {
// given - banner with w=300, h=null, no format, adSlot without size: should error
final BidRequest bidRequest = givenBidRequest(
impBuilder -> impBuilder.banner(Banner.builder().w(300).build()),
extImpPubmaticBuilder -> extImpPubmaticBuilder.adSlot("slot"));

// when
final Result<List<HttpRequest<BidRequest>>> result = target.makeHttpRequests(bidRequest);

// then
assertThat(result.getErrors())
.containsExactly(BidderError.badInput("No sizes provided for Banner"));
assertThat(result.getValue()).isEmpty();
}

@Test
public void makeHttpRequestsShouldNotReturnErrorForInterstitialBannerWithNoSizes() {
// given - per OpenRTB 2.6, banner sizes are optional for interstitial imps (instl=1)
final BidRequest bidRequest = givenBidRequest(
impBuilder -> impBuilder
.instl(1)
.banner(Banner.builder().build()),
extImpPubmaticBuilder -> extImpPubmaticBuilder.adSlot("slot"));

// when
final Result<List<HttpRequest<BidRequest>>> result = target.makeHttpRequests(bidRequest);

// then
assertThat(result.getErrors()).isEmpty();
assertThat(result.getValue()).hasSize(1);
}

@Test
public void makeHttpRequestsShouldAllowBannerWithNoFormatWhenAdSlotProvidesSize() {
// given
final BidRequest bidRequest = givenBidRequest(
impBuilder -> impBuilder.banner(Banner.builder().build()));

// when
final Result<List<HttpRequest<BidRequest>>> result = target.makeHttpRequests(bidRequest);

// then
// Default givenBidRequest adSlot is "slot@300x250", so dimensions come from adSlot
assertThat(result.getErrors()).isEmpty();
assertThat(result.getValue())
.extracting(HttpRequest::getPayload)
.flatExtracting(BidRequest::getImp)
.extracting(Imp::getBanner)
.extracting(Banner::getW)
.containsExactly(300);
assertThat(result.getValue())
.extracting(HttpRequest::getPayload)
.flatExtracting(BidRequest::getImp)
.extracting(Imp::getBanner)
.extracting(Banner::getH)
.containsExactly(250);
}



@Test
public void makeHttpRequestsShouldSetTagIdForBannerImpsWithSymbolsFromAdSlotBeforeAtSign() {
// given
Expand Down