Skip to content

Convenience function ignores createRoadFeatures/createWaterFeatures=False (still passes road/water as featureMasks) #171

Description

@amarcozzi

Summary

When a user calls export_roi / export_roi_to_quicfire with features_config={'createRoadFeatures': False, 'createWaterFeatures': False}, the SDK correctly skips creating the road and water features — but it still asks the API to use those features as featureMasks in the surface grid and tree inventory. The downstream API calls then reference features that were never created, which causes the export to fail (or, in the road case, hang until the API timeout).

This was reported by a QUIC-Fire GUI user who supplied exactly that features_config and got a traceback anyway. They also separately reported the road feature getting stuck on RUNNING for ~5 minutes before timing out on the default path; that report is consistent with the same masking dependency cascading from a backend road-processing regression — the default surface/tree-inventory pipelines both wait on the road feature because of the hardcoded masks.

Reproduction

from fastfuels_sdk import export_roi_to_quicfire

export_roi_to_quicfire(
    roi=roi,
    export_path=\"out.zip\",
    features_config={
        \"createRoadFeatures\": False,
        \"createWaterFeatures\": False,
    },
)

Expected: surface grid / tree inventory are built without any road or water feature masking.
Actual: surface grid and tree inventory are built with featureMasks=[\"road\", \"water\"], so the API job fails (or hangs) because the masks reference features that don't exist for this domain.

Root cause

fastfuels_sdk/convenience.py propagates createRoadFeatures / createWaterFeatures only to the feature-creation block (lines 624-636) and to the feature grid (lines 644-657, which correctly ends up with feature_grid = None). The hardcoded \"featureMasks\": [\"road\", \"water\"] entries in the other defaults are never sanitized:

  • DEFAULT_SURFACE_CONFIGfuelLoad (line 76), fuelDepth (line 84), fuelMoisture (line 90)
  • DEFAULT_TREE_INVENTORY_CONFIG (line 109)

Those merged configs are then handed to _configure_surface_builder and _create_tree_inventory, which forward the masks to SurfaceGridBuilder.with_* and Inventories.create_tree_inventory_from_treemap respectively — even when both feature-creation flags are False.

Proposed fix

After merging user configs with defaults, sanitize the featureMasks lists on merged_surface_config (fuelLoad, fuelDepth, fuelMoisture) and merged_tree_inventory_config so that:

  • \"road\" is stripped whenever createRoadFeatures is False
  • \"water\" is stripped whenever createWaterFeatures is False

This should run after the user merge so an explicit user-supplied featureMasks is also sanitized — the user should not be able to mask against a feature that won't exist.

Add a regression test in tests/test_convenience_config.py that runs export_roi_to_quicfire with both flags False and asserts that no feature_masks containing \"road\" or \"water\" are passed to any builder or inventory call.

Workaround for affected users

Until the fix lands, users disabling road/water features must also clear featureMasks everywhere they appear. For example:

features_config = {\"createRoadFeatures\": False, \"createWaterFeatures\": False}
surface_config = {
    \"fuelLoad\":     {\"featureMasks\": []},
    \"fuelDepth\":    {\"featureMasks\": []},
    \"fuelMoisture\": {\"featureMasks\": []},
}
tree_inventory_config = {\"featureMasks\": []}

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions