While migrating a GoldenGate classic architecture setup with the migration utility, I recently had the following OGG-12020 error:

[ERROR] OGG-12020 - The request payload for 'POST /services/v2/config/files/ext.prm' is not defined as an object

It is a very cryptic error at first glance, but let’s try to understand what happened.

Where does the error come from ?

The first step is to understand what is causing the issue. For this, you need to understand how the GoldenGate migration utility works.

When migrating extracts (or any other GoldenGate object), GoldenGate will make API calls to the new microservices architecture administration service to register the extracts. The OGG-12020 error is just the API telling you that the POST call is invalid.

Let’s use the API log reader from a previous blog post to ease the analysis. You can also just read through the restapi.log of your target deployment, but it will be harder to read.

python3 restapi_to_ndjson.py $OGG_DEPLOYMENT_HOME/var/log restapi.ndjson

Using jq, we filter the failed POST calls against the URI given in the migration logs (/services/v2/config/files/ext.prm).

> jq -c 'select (.request.context.verb == "POST" and .request.context.uri == "/services/v2/config/files/ext.prm" and .restapi_status == "ERROR")' restapi.ndjson
{"request":{"context":{"httpContextKey":140077954104240,"verbId":4,"verb":"POST","originalVerb":"POST","uri":"/services/v2/config/files/ext.prm","protocol":"https","headers":{"Authorization":"** Masked **","Content-type":"application/json","User-Agent":"Java/1.8.0_482","Host":"oggma:port","Accept":"text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2","Connection":"keep-alive","Content-Length":"12417", "Content-Type":null,"X-OGG-Requestor-Id":"","X-OGG-Feature-List":""},"host":"oggma:port","securityEnabled":true,"authorization":{"authUserName":"ogg_user","authPassword":"** Masked **", "authMode":"Basic","authUserRole":"Security"},"requestId":5,"uriTemplate":"/services/{version}/config/files/{file}"},"content":null,"isScaRequest":true,"parameters":{"uri":{"file":"ext.prm","version":"v2"}}},"response":{"context":{"httpContextKey":140077954104240,"requestId":5,"code":"400 Bad Request","headers":{"Content-Type":"application/json","Strict-Transport-Security":"max-age=31536000;includeSubDomains","Set-Cookie":"** Masked **"},"Content-Type":"application/json","contentType":"text/html"},"isScaResponse":true,"content":{"$schema":"api:standardResponse","links":[{"rel":"canonical","href":"https://oggma:port/services/v2/config/files/ext.prm","mediaType":"text/html"},{"rel":"self","href":"https://oggma:port/services/v2/config/files/ext.prm","mediaType":"text/html"}],"messages":[{"$schema":"ogg:message","title":"The request payload for 'POST /services/v2/config/files/ext.prm' is not defined as an object.","code":"OGG-12020","severity":"ERROR","issued":"2026-03-05T09:55:24Z","type":"https://docs.oracle.com/en/middleware/goldengate/core/23.26/error-messages/"}]}},"restapi_datetime":"2026-03-05 10:55:24.448+0100","restapi_epoch":1772704524,"restapi_status":"ERROR","restapi_service":"adminsrvr","restapi_reqno":18}

You might not see the root cause at first, but if we only retrieve the content object:

> jq -c 'select (.request.context.verb == "POST" and .request.context.uri == "/services/v2/config/files/ext.prm" and .restapi_status == "ERROR") | {content:.request.content, message:.response.content.messages[0].title}' restapi.ndjson
{"content":null,"message":"The request payload for 'POST /services/v2/config/files/ext.prm' is not defined as an object."}

The migration utility is sending a request to the API with a null content, which obviously fails. Normally, the content key should contain a list with all the lines from the parameter file.

How to solve this issue ?

Unfortunately, there is no easy solution here. But here are the steps I took to solve the issue.

  • First, you should make sure that the dryrun of the migration utility did not highlight any error in the formatting of the file.
  • Then, make sure you are using the latest version of the migration utility.
  • If it still doesn’t work, you unfortunately found a bug in the migration utility, and there is little you can do.

However, you can still use the tool to migrate. In my case, I managed to pinpoint the error to this line of the extract parameter file:

TOKENS (
    [...]
    TK_COL = [...] @STRSUB(column_name, '|', '\|', '\', '\\') [...]
);

The migration utility seems to have poor handling of these escape characters and does not fail properly. It should either fail before attempting the API call or send proper content to the API.

If you are sure that the incriminated syntax is valid in your target GoldenGate version, migrate with the following steps:

  • Remove the incriminated syntax from the file. In my case, it meant removing the STRSUB section of the file.
  • Migrate with the temporary parameter file
  • Modify the parameter file in the target GoldenGate deployment, undoing the changes.

If you have a lot of extracts and replicats that need to be migrated, using this temporary file trick might be your best chance to secure your GoldenGate migration.