{"record":{"id":"b7d9452079635687","repo":"apache/beam","slug":"the-first-argument-of-the-prev-operation-should-be-a-field","errorCode":null,"errorMessage":"the first argument of the PREV operation should be a field reference. Provided: ${class}","messagePattern":"the first argument of the PREV operation should be a field reference\\. Provided: (.+?)","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"sdks/java/extensions/sql/src/main/java/org/apache/beam/sdk/extensions/sql/impl/nfa/NFA.java","lineNumber":566,"sourceCode":"                \"the function is not supported for now: \" + operator.getCepKind().toString());\n        }\n      } else {\n        throw new IllegalStateException(\n            \"the right side CEP operation is not legal: \" + inputOperation.getClass().toString());\n      }\n    }\n\n    /* below are function implementations */\n\n    // represents the PREV operation\n    private CEPLiteral prev(\n        CEPOperation opr1,\n        CEPLiteral opr2,\n        EventPointer curPointer,\n        Event curEvent,\n        Event inputEvent) {\n      if (opr1.getClass() != CEPFieldRef.class) {\n        throw new IllegalStateException(\n            \"the first argument of the PREV operation should be a field reference. Provided: \"\n                + opr1.getClass().toString());\n      }\n      if (opr2.getTypeName() != Schema.TypeName.DECIMAL) {\n        throw new IllegalStateException(\n            \"the second argument of the prev operation should be a decimal. Provided: \"\n                + opr2.getClass().toString());\n      }\n      // if the second argument is 0, return the current event\n      if (opr2.getDecimal().intValue() == 0) {\n        return inputEvent.toCEPLiteral((CEPFieldRef) opr1);\n      }\n      // for the starting event, return null\n      if (curEvent == null) {\n        return null;\n      }\n      CEPFieldRef fieldRef = (CEPFieldRef) opr1;\n      String alpha = fieldRef.getAlpha(); // the patternVar","sourceCodeStart":548,"sourceCodeEnd":584,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/java/extensions/sql/src/main/java/org/apache/beam/sdk/extensions/sql/impl/nfa/NFA.java#L548-L584","documentation":"The PREV operation in a MATCH_RECOGNIZE pattern must take a field reference as its first argument, because PREV looks up a column value of a previous event. The NFA's StateLocator receives some other CEPOperation subclass (e.g. a literal or arithmetic expression) and throws IllegalStateException, since there is no meaningful 'previous value' of a non-column expression.","triggerScenarios":"Calling PREV with a first argument that is not a CEPFieldRef, e.g. PREV(1) or PREV(some expression) in the DEFINE clause, or invoking the StateLocator/prev path programmatically with a non-CEPFieldRef opr1.","commonSituations":"Misremembering PREV syntax and passing a constant or computed expression instead of a column reference; generated SQL from an ORM/tool that emits unsupported argument shapes.","solutions":["Change the first PREV argument to a plain field reference, e.g. PREV(PRICE, 1)","Verify the parsed AST (opr1.getClass()) is CEPFieldRef if constructing CEPOperation nodes programmatically","Check Beam SQL CEP docs for the exact PREV signature: PREV(field, offset-decimal)"],"exampleFix":"// before\nDEFINE e AS PREV(1, 1)\n// after\nDEFINE e AS PREV(PRICE, 1)","handlingStrategy":"validation","validationCode":"// validate PREV argument before building/running the query\nif (!(prevFirstArg instanceof CEPFieldRef)) {\n  throw new IllegalArgumentException(\"PREV requires a field reference\");\n}","typeGuard":"boolean isFieldRef(CEPOperation op) {\n  return op instanceof CEPFieldRef;\n}","tryCatchPattern":"try {\n  runCepQuery(pattern);\n} catch (IllegalStateException e) {\n  if (e.getMessage().startsWith(\"the first argument of the PREV operation\")) {\n    // rewrite the pattern to use a plain field reference\n  } else throw e;\n}","preventionTips":["Always write PREV(<column>, <numeric literal>) — never constants or expressions as the first argument","Add a query lint in your tooling that rejects PREV/LAST with non-column first args","Consult the Beam CEP docs for exact operator signatures"],"tags":["sql","cep","argument-type"],"backgroundTag":"type-mismatch","analyzedSha":"12126d8942aaf848030c478b4c6a28c6af861c66","analyzedAt":"2026-09-13T01:50:10.254Z","contentChangedAt":"2026-09-13T01:50:10.254Z","schemaVersion":2},"datasetVersion":"2026-09-20T03:17:13.778Z"}