APEX 26.1 platform issues – reports for the Oracle APEX development team
The issues below were found while building a custom model-driven APEX region plugin using the public apex.model JavaScript API and the APEX_EXEC PL/SQL package (WWV_FLOW_EXEC_API). Each one is reproducible in isolation, on a minimal model/table, independent of any specific application. Root cause has been verified by reading the actual client/ server source involved, not only inferred from the symptom.
Each numbered item below is written to be posted as its own forum thread / SR. A suggested workaround is included where one was found and applied.
Bug reports
1. apex.model, shape "record": a second save after a first successful save sends stale data
- Component:
apex.model(client JavaScript), internal function_updateData(). - Environment: Oracle APEX 26.1, any browser (verified via network capture — not browser-specific).
- Steps to reproduce:
- Create an
apex.modelinstance withshape: "record". - Call
setValue()on a field, thenmodel.save(). Let it complete successfully. - Call
setValue()again (on any field, including the same one), thenmodel.save()a second time.
- Create an
- Expected: the second save request carries the record’s current value.
- Observed: the second save silently sends the value as it stood right after the first save, not the value set afterward.
model.getRecord()becomes stale from that point on. - Root cause (verified in source): after a successful save,
_updateData()reconciles withthis._data[iNode.index] = rec— correct only forshape: "table", where_datais an indexed collection. Forshape: "record",getRecord()returnsthis._datadirectly (getRecord = function() { return that._data; }), neverthis._data[index]— so this reconciliation line never updates the objectgetRecord()returns. - Suggested workaround: after every successful save on a
shape: "record"model, callmodel.clearData()followed bymodel.fetch()instead of relying on the model’s own post-save reconciliation.
2. apex.model, shape "record": revertRecords() does not update the reference returned by getRecord()
- Component:
apex.model(client JavaScript),revertRecords(). - Environment: Oracle APEX 26.1.
- Steps to reproduce:
- Create an
apex.modelwithshape: "record". - Modify a field with
setValue(). - Call
model.revertRecords()on the record.
- Create an
- Expected:
getRecord()returns the original, pre-modification value. - Observed:
getRecord()still returns the just-modified value. - Root cause (verified in source): in the
shape: "record"branch ofrevertRecords(), the code updatesmetadata.record = metadata.originalbut never reassignsthis._data(whatgetRecord()returns for this shape). The line that would populatethis._datais explicitly skipped by ashape !== RECORDguard, and no alternate branch populates it for shape"record". - Suggested workaround: after calling
revertRecords()on ashape: "record"model, forcemodel.clearData()+model.fetch()instead of trusting the in-memory revert.
3. apex.model, recordIsArray: true: insertNewRecord() does not validate or normalize the init value
- Component:
apex.model(modelViewBase.min.js), internal function_initRecord. - Environment: Oracle APEX 26.1.
- Steps to reproduce:
- Create a model with
recordIsArray: true. - Call
model.insertNewRecord(index, false, initValue), whereinitValueis a plain object (not an array).
- Create a model with
- Expected: either the init value is normalized to an array consistent with
recordIsArray: true, or the public documentation states that a non-array third argument is unsupported in this mode. - Observed: the value is used verbatim as the new record, with no validation — leading to a runtime error the first time the record is treated as an array (
row.values.forEach is not a function). - Root cause (verified in source):
_initRecorduses any truthy third argument directly as the record, with no shape check againstrecordIsArray. - Suggested workaround: omit the third argument when
recordIsArray: true— the model then builds a well-formed, empty array-shaped record on its own.
4. APEX_EXEC.EXECUTE_DML raises ORA-06592 for a DELETE added via OPEN_LOCAL_DML_CONTEXT with query type TABLE
- Component:
APEX_EXEC(PL/SQL), internallyWWV_FLOW_EXEC_API. - Environment: Oracle APEX 26.1, Oracle Database 19c and later.
- Severity: high — an internal
ORA-error surfaces from inside a public, documented package, not an application-level error. - Steps to reproduce:
- On any scratch table, call
APEX_EXEC.OPEN_LOCAL_DML_CONTEXTwithp_query_type => APEX_EXEC.C_QUERY_TYPE_TABLE. - Call
APEX_EXEC.ADD_DML_ROWwithp_dml_operation => APEX_EXEC.C_DML_OPERATION_DELETE, supplying only the primary key column and value. - Call
APEX_EXEC.EXECUTE_DML.
- On any scratch table, call
- Expected: the row is deleted, or an application-level error is raised (permission denied, row not found).
- Observed:
ORA-06592: CASE not found while executing CASE statement, raised from insideWWV_FLOW_EXEC_APIitself. - Verification: reproduced in isolation on a dedicated scratch table, unrelated to any specific application. The public documentation for this API shows only INSERT examples via
ADD_DML_ROW— no DELETE example withp_query_type => C_QUERY_TYPE_TABLE. - Suggested workaround: use
p_query_type => APEX_EXEC.C_QUERY_TYPE_SQL_QUERYwith an equivalent query and the primary key’s real datatype declared explicitly — this path deletes correctly.
5. apex.model: a save batch with more than one DELETE leaves the model/UI inconsistent even after an explicit fetch()
- Component:
apex.model(client JavaScript), post-save reconciliation (_updateData) andmodel.fetch(). - Environment: Oracle APEX 26.1.
- Steps to reproduce:
- In the same browser session, insert and save several rows in an
apex.model-backed table region. - In a single, separate save batch, mark two or more of those rows for deletion and save.
- In the same browser session, insert and save several rows in an
- Expected: after the save completes, the table reflects the correct remaining rows — if necessary, after an explicit
model.fetch(). - Observed: both the model’s automatic post-save reconciliation and an explicit
model.fetch()called immediately afterward are unreliable — the table can appear completely empty despite a successful save with no real conflict. Only a full page reload restores the correct state. - Note for triage: please test the exact sequence above (N inserts+save, then a separate save with M ≥ 2 deletes in the same batch) — the explicit
fetch()call is also affected, not only the automatic reconciliation, so this should not be dismissed as “just call fetch() after save.” - Root cause: not further isolable from outside the platform — the client source is minified beyond the point reached during investigation. This is exactly the kind of case that needs access to the unminified source for further diagnosis.
Documentation clarification request
6. apex.model, shape "table": the post-save identity reconciliation contract does not appear to be publicly documented
- Nature: not a functional defect — the behavior is consistent and stable, but the contract does not appear to be documented publicly. Included here as a documentation request, not a bug.
- Observed behavior: after a save, the client only reconciles a row’s identity (e.g. replacing a temporary client-side id with the real server-generated id after an insert, or removing a row after a delete) if the save response includes a
metaobject — at the same position as the corresponding request row — containingrecordIdequal to the identity previously known to the client. Without thismetaobject, a successful insert leaves the temporary id visible client-side until the next fetch, and a successful delete never removes the row from the client-side model. - Request: could the exact shape of this
meta/recordIdcontract (expected per save-response row, for insert and delete) be documented publicly forapex.modelconsumers implementing a custom Ajax save handler? - Verified by: reading
_updateData()in the client source; no reference to this contract found in the publicapex.model(aexjs) documentation.


No responses yet