api-manager icon indicating copy to clipboard operation
api-manager copied to clipboard

[4.1.0] Unable to create free Subscription policy after configuring Monetization

Open arunans23 opened this issue 3 years ago • 2 comments

Description:

$subject. Getting the following error.

TID: [-1234] [api/am/admin] [2022-05-13 08:00:26,636] ERROR {org.wso2.carbon.apimgt.rest.api.util.exception.GlobalThrowableMapper} - An unknown exception has been captured by the global exception mapper. java.lang.NumberFormatException: empty String
    at java.base/jdk.internal.math.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:1842)
    at java.base/jdk.internal.math.FloatingDecimal.parseFloat(FloatingDecimal.java:122)
    at java.base/java.lang.Float.parseFloat(Float.java:455)
    at org.wso2.apim.monetization.impl.StripeMonetizationImpl.createBillingPlan(StripeMonetizationImpl.java:152)
    at org.wso2.carbon.apimgt.impl.APIProviderImpl.createMonetizationPlan_aroundBody310(APIProviderImpl.java:6243)
    at org.wso2.carbon.apimgt.impl.APIProviderImpl.createMonetizationPlan(APIProviderImpl.java:6238)

Steps to reproduce:

  1. Configure monetization with Stripe https://apim.docs.wso2.com/en/latest/design/api-monetization/monetizing-an-api/

  2. Create a Free Subcription policy

Affected product version:

4.1.0

arunans23 avatar May 13 '22 18:05 arunans23

Fixed with the following PR for v4.4.0: https://github.com/wso2/carbon-apimgt/pull/12427

Chilliwiddit avatar Jan 24 '25 12:01 Chilliwiddit

Fixed in WSO2 API Manager 4.6.0

This issue has been fixed in WSO2 API Manager 4.6.0. FREE subscription policies can now be created successfully even when monetization is configured.

Issue Summary

In APIM 4.1.0, when Stripe monetization was configured, attempting to create a FREE subscription policy threw a NumberFormatException:

java.lang.NumberFormatException: empty String
    at java.base/jdk.internal.math.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:1842)
    at java.base/jdk.internal.math.FloatingDecimal.parseFloat(FloatingDecimal.java:122)
    at java.base/java.lang.Float.parseFloat(Float.java:455)
    at org.wso2.apim.monetization.impl.StripeMonetizationImpl.createBillingPlan(StripeMonetizationImpl.java:152)
    at org.wso2.carbon.apimgt.impl.APIProviderImpl.createMonetizationPlan_aroundBody310(APIProviderImpl.java:6243)

The error occurred because the system tried to create a monetization billing plan (with pricing) for FREE tier policies, which don't have pricing information.

Test Results (APIM 4.6.0)

Test Scenario:

  1. Create a FREE subscription policy
  2. Create a COMMERCIAL subscription policy for comparison
  3. Verify both succeed without errors

Result:FIXED

Step 2: Creating FREE subscription policy...
Policy Name: FreeTier_Test_1763976048
Billing Plan: FREE
Status Code: 201
✓ FREE policy created successfully
  Policy ID: 875c8eaf-e0bf-4db0-988b-79c369d68412

Step 3: Creating COMMERCIAL subscription policy...
Policy Name: CommercialTier_Test_1763976048
Billing Plan: COMMERCIAL
Status Code: 201
✓ COMMERCIAL policy created successfully
  Policy ID: 0ea03b20-3be6-4342-8ccc-75f24b992d61
  • FREE Policy: ✅ Created successfully (HTTP 201)
  • COMMERCIAL Policy: ✅ Created successfully (HTTP 201)
  • NumberFormatException: No errors encountered

Fix Analysis

File: components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/APIProviderImpl.java (lines 4114-4121)

What Changed:

// Before: Hardcoded string comparison
if (subPolicy.getBillingPlan().equalsIgnoreCase("COMMERCIAL")) {
    // Create monetization plan
}

// After: Using constant and proper checks
if (subPolicy.getBillingPlan().equalsIgnoreCase(COMMERCIAL_TIER_PLAN)) {
    String monetizationPlan = subPolicy.getMonetizationPlan();
    Map<String, String> monetizationPlanProperties = subPolicy.getMonetizationPlanProperties();
    if (StringUtils.isNotBlank(monetizationPlan) && MapUtils.isNotEmpty(monetizationPlanProperties)) {
        createMonetizationPlan(subPolicy);
    }
}

Why This Fixes the Issue:

  1. Proper Billing Plan Check: The code now uses the COMMERCIAL_TIER_PLAN constant ("COMMERCIAL") for comparison, ensuring consistency
  2. Conditional Monetization: The createMonetizationPlan() method is only called when:
    • Billing plan is COMMERCIAL (not FREE)
    • Monetization plan name is not blank
    • Monetization plan properties are not empty
  3. Skips FREE Tiers: When a FREE subscription policy is created, the monetization plan creation is completely skipped
  4. No Empty String Parsing: The Stripe monetization implementation never receives empty pricing strings for FREE tiers

Root Cause: Previously, the system attempted to create billing plans for all subscription policies, including FREE tiers. When the Stripe monetization implementation tried to parse the (empty) price value for a FREE tier at line 152:

Float.parseFloat(price)  // price was empty string for FREE tiers

It threw NumberFormatException: empty String.

The Fix: By checking the billing plan type and only creating monetization plans for COMMERCIAL tiers with valid monetization configuration, FREE tiers bypass monetization plan creation entirely, eliminating the NumberFormatException.

Conclusion

FREE subscription policies can now be created successfully regardless of whether monetization is configured. The fix properly distinguishes between FREE and COMMERCIAL billing plans, preventing attempts to create monetization billing plans for policies that don't require pricing information.


Tested on: WSO2 API Manager 4.6.0 Status: ✅ Fixed Test Method: REST API - Created both FREE and COMMERCIAL subscription policies

🤖 Generated with Claude Code

ranuka-laksika avatar Nov 24 '25 09:11 ranuka-laksika