PX script fails with NullPointerException when updating custom attributes in recipe management

I’m developing a Process Extension (PX) script to automatically update custom attributes on Change Orders when they reach the ‘Released’ status. The script works in our test environment but fails in production with a NullPointerException.

Error from the log:


NullPointerException at line 23
at CustomAttributeUpdater.updateFields()
at ChangeStatusHandler.doAction()
Workflow blocked at Released status

The script reads values from one custom attribute (Project_Code) and populates another (Full_Project_Name) by looking up a mapping table. In JavaClient, I can manually inspect both attributes and they exist on the Change object. The PX script error handling seems inadequate because the exception doesn’t provide details about which attribute is null. This is blocking our workflow automation rollout and causing Change Orders to pile up in Released status awaiting manual intervention.

Your NullPointerException is likely caused by insufficient error handling and validation in your PX script. Let me walk through a comprehensive solution addressing all three critical areas.

PX Script Error Handling: PX scripts require defensive programming because they run outside the normal UI validation layer. Here’s the proper error handling structure:

try {
    IChange change = (IChange) obj;
    if (change == null) {
        logger.error("Change object is null");
        return;
    }

    Object projectCodeObj = change.getValue("PROJECT_CODE");
    if (projectCodeObj == null || projectCodeObj.toString().trim().isEmpty()) {
        logger.warn("Project_Code is empty for " + change.getName());
        return;
    }
} catch (Exception e) {
    logger.error("PX failed: " + e.getMessage(), e);
}

The key is checking for null at every step: the object cast, the getValue() result, and the toString() conversion. Production data is messier than test data, so null values are more common.

Custom Attribute Validation: The difference between test and production likely involves data quality. In JavaClient inspection, you’re viewing attributes with your admin privileges, but the PX runs under a different context. Validate attributes programmatically:

  1. Check attribute existence: Before accessing custom attributes, verify they exist on the Change class in production. Use IAdmin.getAgileClass() to retrieve the class definition and confirm the attribute is configured.

  2. Verify attribute accessibility: The PX service account needs explicit read/write privileges for custom attributes. Check Admin > Roles & Privileges > [PX Service Role] > Attributes tab. If Project_Code or Full_Project_Name aren’t in the accessible list, getValue() returns null silently.

  3. Handle empty vs. null: Agile treats empty strings and null differently depending on attribute type. Text attributes might store empty string (‘’), while list attributes store null when unselected. Your code should handle both:

String projectCode = "";
if (projectCodeObj != null) {
    projectCode = projectCodeObj.toString().trim();
}
if (projectCode.isEmpty()) {
    // Handle empty case
}

JavaClient Inspection vs. PX Context: JavaClient shows you what exists in the database, but PX sees what’s accessible through the API at workflow execution time. The discrepancy suggests:

  1. Timing issue: When the workflow reaches ‘Released’ status, custom attributes might not be committed to the database yet. Add a small delay or verify the Change is fully saved before accessing attributes.

  2. Transaction scope: PX scripts run within a transaction. If the attribute update triggering your PX hasn’t been committed, getValue() might return the old (null) value. Use IChange.getValueByName() with the correct transaction context.

  3. Cascade loading: Custom attributes on related objects (like affected items) aren’t always loaded automatically. If Project_Code is on an affected item rather than the Change itself, you need to explicitly load the item first.

Complete Solution:

  1. Add comprehensive logging:

    • Log the Change number and status at script entry
    • Log each attribute value before processing
    • Log the mapping table lookup result
    • Log the final attribute update
  2. Implement graceful degradation: Instead of blocking the workflow, allow the Change to proceed and flag it for manual review if attributes are missing. Add a custom flag attribute ‘PX_Failed’ that you set to true when validation fails.

  3. Pre-validation check: Add a PX at an earlier workflow status (like ‘Submitted’) that validates required attributes are populated. This prevents Changes from reaching ‘Released’ with missing data.

  4. Production debugging: Temporarily enable DEBUG logging for your PX class in production (Admin > Server Settings > Logging). Reproduce the issue with one test Change, then immediately disable DEBUG to avoid log bloat.

  5. Permissions audit: Export the PX service account’s role privileges and compare against your admin account. The difference will reveal which attributes the PX can’t access.

After implementing these changes, your PX should handle edge cases gracefully and provide enough logging to diagnose any remaining issues without blocking workflows.

Yes, validate everything. Check if the Change object itself is not null, then check if getValue() returns null before calling any methods on the returned value. In production, empty string values might be stored as null, while test might have empty strings. Your code needs to handle both cases.

Classic PX debugging issue. Add null checks before every attribute access. The problem is likely that Project_Code is empty on some Change Orders. PX scripts don’t have the same default value handling as the UI. Wrap your attribute reads in try-catch blocks and log the actual values you’re getting.

Also check if the custom attribute field IDs are different between test and production. If someone recreated the fields instead of migrating them, the internal IDs won’t match. Your script might be trying to access a field that doesn’t exist in prod, causing the null reference. Use the field’s API name instead of internal ID for better portability.

Check your PX privileges. If the script runs under a service account that doesn’t have read access to those custom attributes, getValue() can return null even though the field exists. JavaClient inspection works because you’re using your admin account. The PX might be running with different permissions in production.

Good points. I verified the field API names match between environments. I’ve added logging, but the PX log level in production is set to ERROR only, so I’m not seeing my debug output. Nina, how detailed should the null checks be? Should I validate the attribute exists on the object before trying to read it?