Skip to content

BUG: C12: Error code reused in 23 filters #1872

Open

Description

@imikejackson

Summary

Some filters return the same error code (or warning code) for two or more different conditions. Some filters also use a code that another filter or a shared utility already uses. A user, a test or a calling application then cannot tell from the code which check failed. As of develop 419f9db (2026-10-21), this class has 23 open findings in 23 filters: 0 CRASH, 0 WRONG_DATA, 23 MINOR. All findings are MINOR: no finding causes a crash or incorrect output.

Mechanism

Error codes are integer literals or file-local constants. When a developer adds a check, they often copy the code from the check above it. No tool checks that each code is used for one condition only. Shared utilities (Actions, FileUtilities, DatasetIO, VtkUtilities, ImageGeometryCrop) also return codes that can be the same as the codes of the filter that calls them.

Example: AppendImageGeometryFilter returns -8201 for a Y-dimension mismatch and for a Z-dimension mismatch (AppendImageGeometryFilter.cpp#L129-L136):

    if((pDirection == CopyFromArray::Direction::X || pDirection == CopyFromArray::Direction::Z) && destGeomDims[1] != inputGeomDims[1])
    {
      return MakePreflightErrorResult(-8201, fmt::format("Input Y Dim ({}) not equal to Destination Y Dim ({})", inputGeomDims[1], destGeomDims[1]));
    }
    if((pDirection == CopyFromArray::Direction::X || pDirection == CopyFromArray::Direction::Y) && destGeomDims[2] != inputGeomDims[2])
    {
      return MakePreflightErrorResult(-8201, fmt::format("Input Z Dim ({}) not equal to Destination Z Dim ({})", inputGeomDims[2], destGeomDims[2]));
    }

Fixed form (#1767, commit 53c678d): QuickSurfaceMeshScanline.cpp returned -56342 for an empty mesh. That code is also k_NoFacesPrunedWarning in TriangleUtilities.hpp. The fix moved the error to an unused code in the filter's own block (QuickSurfaceMeshScanline.cpp#L81-L84):

  if(nodeCount == 0)
  {
    return MakeErrorResult<std::unique_ptr<ITemporaryRecordStore>>(-56346, "QuickSurfaceMesh cannot create node state for an empty mesh.");
  }

Rule

  • Each condition gets its own error code. Each warning condition gets its own warning code.
  • Filter error codes are more negative than -10000. Each filter uses one range of 100 codes. Example: if the first code is -47500, all codes of that filter are in -47500..-47599.
  • A new code must not be used anywhere else in the repository or in an open pull request.
  • Checks belong in preflight unless they need array values.

How to fix

  1. For each finding, find all uses of the duplicated code in the filter, its algorithm and the utilities it calls.
  2. Keep the code on the condition that existing tests already assert. Give the other condition a new code.
  3. Take the new code from the filter's own range. If the filter has no range more negative than -10000, choose one free block of 100 codes more negative than -10000 for its new codes.
  4. For a shared utility (for example CreateAttributeMatrixAction, RenameDataAction, ValidateCSVFile, DatasetIO, VtkUtilities), choose codes that no filter uses.
  5. Check that the new code is unique. Use git grep -nE -- "-NNNN([^0-9]|$)". Do not use \b, because git grep -E ignores it. Run the same search on each open pull request ref.
  6. Prefer a named constant (for example constexpr int32 k_ZDimMismatch = -NNNNN;) in the filter source file. Use the same constant in preflight and execute when they report the same condition.
  7. Update every test and every documentation page that names the old code for the moved condition.
  8. If a finding shows other defects in the same lines (a wrong value in the message, a check in the wrong mode), fix them in the same commit and write that in the commit message.

How to test

  • Write the test first. It must fail on develop.
  • For each finding, add one test per condition that shares the code. Each test triggers one condition and asserts its exact code, for example REQUIRE(result.errors()[0].code == k_ZDimMismatch).
  • The test for the condition that gets the new code fails on develop, because develop returns the old code.
  • Use preflight tests when the check is in preflight. Use execute tests only for execute-time checks.
  • Some conditions are hard to cause in a test (a disk-full write, a short read from an external sort). If you cannot cause the condition, write that in the PR and on this issue, and change the code without a new test.

Conventions

  • One PR for the whole class. One commit per filter. Commit prefix BUG:. Add a Signed-off-by line. Do not add AI attribution.
  • Every fix starts with a unit test that fails on develop. If you cannot reproduce a finding, write that and the reason in the PR and on this issue. Do not force a fix.
  • Value checks need an independent expected result (oracle), not the output of the code under test.
  • Run ctest serially. Never use -j, because the tests depend on each other.
  • Format with clang-format 19.1.1 and the repository .clang-format.
  • Do not add per-filter documentation sentences about input requirements. The generated parameter table documents them.
  • If a fix touches a filter that has a V&V report (src/Plugins/<Plugin>/vv/<Filter>.md), update every file of that filter's V&V package (report, deviations, provenance, test tables). V&V documents reference DREAM3D 6.5.171 only.
  • Rebase on develop. Never merge develop into the branch.

Checklist

  • MINOR · AppendImageGeometryFilter · AppendImageGeometryFilter.cpp:135 — Code -8201 is returned both for a Y-dimension mismatch (line 131) and for a Z-dimension mismatch (line 135). AppendImageGeometryFilter#7
  • MINOR · ApplyTransformationToGeometryFilter · GeometryTransformation.cpp:169 — Code -82006 is returned both for a matrix that does not have exactly 4 columns (line 103) and for the interpolation/Cell Attribute Matrix error (line 169). ApplyTransformationToGeometryFilter#11
  • MINOR · ArrayCalculatorFilter · ArrayCalculator.cpp:540 — simulateShapes returns InvalidEquation (-4009) for a missing operand and for other conditions; the MissingArguments code (-4032) is never used. ArrayCalculatorFilter#10
  • MINOR · ComputeArrayStatisticsFilter · ComputeArrayStatistics.cpp:1891 — Code -57305 is returned for four different conditions (lines 1826, 1885, 1891, 1895), -57306 for two, and -563501 for both mask and cast failures. ComputeArrayStatisticsFilter#7
  • MINOR · ComputeDifferencesMapFilter · ComputeDifferencesMapFilter.cpp:21 — Code -90004 is the tuple-count error (line 176) and also the uint8 warning (line 57). ComputeDifferencesMapFilter#2
  • MINOR · ConvertColorToGrayScaleFilter · ColorToGrayScale.cpp:33 — Code -10704 is returned both for a negative weight (line 33) and for a weight sum outside 0.98..1.02 (line 39). ConvertColorToGrayScaleFilter#4
  • MINOR · CreateAttributeMatrixFilter · CreateAttributeMatrixAction.cpp:52 — Code -5205 is returned both for 'Parent Id was not available' (line 46) and for an Attribute Matrix inside another Attribute Matrix (line 52). CreateAttributeMatrixFilter#2
  • MINOR · CropImageGeometryFilter · ImageGeometryCrop.cpp:168 — Code -50560 is returned for both 'below min' and 'above max', -50503 for both clamp warnings, and -953 twice in CropImageGeometry.cpp; the below-min message also prints maxPoint instead of minPoint. CropImageGeometryFilter#7
  • MINOR · EbsdToH5EbsdFilter · EbsdToH5Ebsd.cpp:164 — Code -99509 is returned both for an empty generated file list (line 146) and for a failed Manufacturer write for .ang input (line 164). EbsdToH5EbsdFilter#2
  • MINOR · ExtractInternalSurfacesFromTriangleGeometryFilter · ExtractInternalSurfacesFromTriangleGeometryFilter.cpp:215 — Code -2071 and one generic tuple-count message are used for three checks (lines 161, 215, 240), so the user cannot tell which parameter is wrong. ExtractInternalSurfacesFromTriangleGeometryFilter#1
  • MINOR · InterpolatePointCloudToRegularGridFilter · InterpolatePointCloudToRegularGridFilter.cpp:174 — Codes -11000 (kernel, sigma) and -11002 (interpolate, copy) are each used twice; the sigmas are also checked in Uniform mode, where they are hidden. InterpolatePointCloudToRegularGridFilter#5
  • MINOR · ReadCSVFileFilter · FileUtilities.cpp:93 — ValidateCSVFile returns -301 both when the input is a directory (line 93) and when the file does not open (line 101). ReadCSVFileFilter#6
  • MINOR · ReadGrainMapper3DFilter · ReadGrainMapper3D.cpp:498 — Code -89350 is returned both when the AbsorptionCT group does not open (line 479) and when the input file does not open (line 498). ReadGrainMapper3DFilter#9
  • MINOR · ReadHDF5DatasetFilter · DatasetIO.cpp:446 — DatasetIO::getDataType returns -20012, -20013 and -20014, which are also the filter's own codes at lines 196, 275 and 289 for different conditions. ReadHDF5DatasetFilter#2
  • MINOR · ReadMhaFileFilter · MetaImageUtilities.cpp:476 — Code -35806 is returned for a non-numeric NDims, a bad DimSize token, a bad ElementNumberOfChannels and a DimSize/NDims count mismatch, so the code does not tell which header field is wrong. ReadMhaFileFilter#3
  • MINOR · ReadStlFileFilter · ReadStlFileFilter.cpp:137 — Preflight uses the negative triangle count read from the file header as the error code, while execute uses k_TriangleCountParseError for the same condition. ReadStlFileFilter#5
  • MINOR · ReadZeissTxmFileFilter · ReadZeissTxmFile.cpp:262 — Code -33520 is returned both when a crop bound maps outside the volume (line 142) and for an unsupported TXM data type (line 262). ReadZeissTxmFileFilter#4
  • MINOR · RegionalMaximaImageFilter · RegionalMaximaImageFilter.cpp:22 — k_NonFiniteValue = -8573 collides with k_GradientMagnitudeZeroSpacing = -8573 in ImageProcessingConstants.hpp; the comment says the block is free, but it is not. RegionalMaximaImageFilter#1
  • MINOR · RenameDataObjectFilter · RenameDataAction.cpp:81 — Code -6601 is returned both for 'Source DataPath does not exist' (line 62) and for the parent-container conflict (line 81). RenameDataObjectFilter#4
  • MINOR · RequireMinimumSizeFeaturesFilter · RequireMinimumSizeFeaturesFilter.cpp:129 — Preflight returns -k_BadMinAllowedFeatureSize, which is the positive value +5555, and execute reuses -5555 for 'phase not available'. RequireMinimumSizeFeaturesFilter#4
  • MINOR · WriteAbaqusHexahedronFilter · WriteAbaqusHexahedron.cpp:418 — Code -1117 is returned both for the master-file write error (line 418) and for the external-sort short read in utils/AbaqusElementSets.cpp:332. WriteAbaqusHexahedronFilter#3
  • MINOR · WriteStlFileFilter · WriteStlFile.cpp:440 — Code -27874 is the preflight error 'Part Number Array doesn't exist' and also the grouped-mode warning for a header longer than 80 characters; the single-file path uses -27884 for that warning. WriteStlFileFilter#4
  • MINOR · WriteVtkRectilinearGridFilter · VtkUtilities.hpp:211 — Code -2090 is returned for a source-array read failure (line 211) and for two file-write failures (lines 223 and 237). WriteVtkRectilinearGridFilter#6

Already fixed or in progress

Out of scope

  • Findings in filters that have a V&V report are not in this issue. There are 5: ComputeAvgOrientationsFilter, DBSCANFilter, ReadCtfDataFilter, RemoveFlaggedFeaturesFilter, WritePoleFigureFilter. A separate V&V branch handles them.
  • Renumbering the existing codes of a filter into one block more negative than -10000 is not part of this issue. Change only the codes that the findings name.
  • Every finding is a candidate. It was found and re-checked by reading the code at develop 419f9db, not by running it.

Activity

  1. changed the title [-]BUG: Error code reused in 23 filters[/-] [+]BUG: C12: Error code reused in 23 filters[/+] on Oct 22, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions