{"record":{"id":"36a37cd48c403002","repo":"apache/iceberg","slug":"no-column-at-position-colpos","errorCode":null,"errorMessage":"No column at position ${colPos}","messagePattern":"No column at position (.+?)","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"core/src/main/java/org/apache/iceberg/deletes/PositionDelete.java","lineNumber":70,"sourceCode":"    return path;\n  }\n\n  public long pos() {\n    return pos;\n  }\n\n  @Override\n  @SuppressWarnings(\"unchecked\")\n  public <T> T get(int colPos, Class<T> javaClass) {\n    switch (colPos) {\n      case 0:\n        return (T) path;\n      case 1:\n        return (T) (Long) pos;\n      case 2:\n        return (T) row;\n      default:\n        throw new IllegalArgumentException(\"No column at position \" + colPos);\n    }\n  }\n\n  @Override\n  public <T> void set(int colPos, T value) {\n    switch (colPos) {\n      case 0:\n        this.path = (CharSequence) value;\n        break;\n      case 1:\n        this.pos = (Long) value;\n        break;\n      case 2:\n        this.row = (R) value;\n        break;\n      default:\n        throw new IllegalArgumentException(\"No column at position \" + colPos);\n    }","sourceCodeStart":52,"sourceCodeEnd":88,"githubUrl":"https://github.com/apache/iceberg/blob/86d9c8fc543e7c56c9f624eb725f76c9baff9570/core/src/main/java/org/apache/iceberg/deletes/PositionDelete.java#L52-L88","documentation":"PositionDelete models a row as a 3-element struct: position 0 = file path, 1 = position, 2 = the deleted row (nullable). get(colPos) throws IllegalArgumentException for any index outside 0..2, since there are only three logical columns.","triggerScenarios":"Calling PositionDelete.get(3) or higher (or negative), e.g. when generic struct-like access code iterates a schema with more columns than PositionDelete actually has.","commonSituations":"Generic readers projecting a table schema's column count onto a PositionDelete instance; off-by-one loops over columns; assuming the row struct's fields are addressable directly via get().","solutions":["Only use colPos values 0, 1, or 2; access row fields through the row object (a StructLike or row type) instead","Bounds-check colPos against the logical arity of 3 before calling get","If iterating generically, cap iteration at PositionDelete's size (3)","For row-level columns, cast get(2) to the row type and index into that"],"exampleFix":"// before\nfor (int i = 0; i < schema.columns().size(); i++) {\n  Object v = positionDelete.get(i); // throws at i >= 3\n}\n// after\nObject path = positionDelete.get(0);\nLong pos = positionDelete.get(1);\nR row = positionDelete.get(2); // access row fields via row\n","handlingStrategy":"validation","validationCode":"if (colPos < 0 || colPos > 2) {\n  throw new IllegalArgumentException(\"PositionDelete has only 3 columns (0=path, 1=pos, 2=row)\");\n}","typeGuard":"static boolean isValidColumn(int colPos) {\n  return colPos >= 0 && colPos <= 2;\n}","tryCatchPattern":"try {\n  return positionDelete.get(colPos);\n} catch (IllegalArgumentException e) {\n  throw new IllegalArgumentException(\"colPos must be 0-2 for PositionDelete\", e);\n}","preventionTips":["Remember PositionDelete arity is fixed at 3 (path, position, row)","Index row fields on the row object from get(2), not via PositionDelete.get","Guard generic schema-driven loops with arity min(schema.size(), 3)","Add asserts in helper utilities that wrap PositionDelete access"],"tags":["illegal-argument","bounds-check","position-delete"],"backgroundTag":"index-out-of-range","analyzedSha":"86d9c8fc543e7c56c9f624eb725f76c9baff9570","analyzedAt":"2026-09-12T00:46:39.097Z","contentChangedAt":"2026-09-12T00:46:39.097Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}