RECORD SAVE - CloudKit wouldn't accept a LIST of STRING as a field
What type of issue is this?
Bug
What is incorrect, incomplete, or missing?
Hi, I am trying to save a record in which one of the fields is a list of strings. I am creating an array of RecordFields of type "STRING" and passing it as a RecordField of type "LIST"'s value. There are no errors thrown by the compiler. Problem is when I send the request, I get "BadRequestException: Unexpected input". From what I understand it should work.
What platforms does this issue apply to, if applicable?
No response
What did you expect to see?
Record saved successfully
How did you test this?
I ran the code using nextjs hosted on vps.
Can you link to a related release note, pull request, or page?
No response
Do you have anything more you want to share?
No response
Hello, @inferutsers!
Thank you for the report. Please provide more information about the implementation. From what I understand you are using the wrong type as indicated by the server.
The CloudKit JS documentation contains a link to the correct type setting for each value type.
Maybe this already helps.
Hello
This is the record I am trying to save:
const record: RecordToCreate = { recordType: "TestType", fields: { "testList": { type: "LIST", value: listArray } };
listArray is:
const list = ["string1", "string2"]; const listArray: RecordField[] = list.map((e) => {return {type: "STRING", value: e} as RecordField});
And from apple's api I am getting: _ckErrorCode: 'BAD_REQUEST', _reason: 'BadRequestException: Unexpected input', _serverErrorCode: 'BAD_REQUEST'
If you need any more info I am happy to provide you with that.
Thanks. Your code looks correct. I have to create a test case tomorrow to see, if I can reproduce the issue.
Just a hunch, but maybe CloudKit JS does the array mapping now. It is worth a try to assign the string array with an any-cast as the direct value:
const list = ["string1", "string2"];
const record: RecordToCreate = {
recordType: "TestType",
fields: {
"testList": { type: "LIST", value: list as any }
}
};
I tested your hunch but it doesn't seem to make a difference. Let's see if you can reproduce the issue tomorrow.
Any new info? Still wondering whether its something on my end.
Hello!
Sorry for the delay. I have issues with my CloudKit profiles and could not test yet.
I can only think of two other fields for failure:
-
The container might not be configured properly, either the types, or created for iOS app and not web app.
-
The encoding of the strings might be an issue.
If I get the profile issues solved, I will run some tests this weekend.
Hello, there is the schema for the context:
RECORD TYPE TestType (
"___createTime" TIMESTAMP,
"___createdBy" REFERENCE,
"___etag" STRING,
"___modTime" TIMESTAMP,
"___modifiedBy" REFERENCE,
"___recordID" REFERENCE QUERYABLE,
testList LIST<STRING> QUERYABLE,
GRANT WRITE TO "_creator",
GRANT READ, CREATE, WRITE TO "_icloud",
GRANT READ TO "_world"
);
I don't really know what you mean by "created for iOS app and not web app". For my knowledge all containers are created through identifiers. Quoting Apple's documentation: "In CloudKit Dashboard, enable web services by creating either an API token or server-to-server key". There is a server-to-server key created and actively used to perform queries.
Also, if that helps:
CloudKitJS CloudKit Database#saveRecords [
{
recordType: 'TestType',
fields: {
testList: [Object]
}
}
] {}
CloudKitJS RecordsBatchBuilder#createOrUpdate [
{
recordType: 'TestType',
fields: {
testList: [Object]
}
}
] {}
CloudKitJS RecordsBatchBuilder#create {
recordType: 'TestType',
fields: {
testList: { type: 'LIST', value: [Array] }
}
} {}
CloudKitJS RecordsBatchBuilder#commit
t [Error]: BadRequestException: Unexpected input
That's the output I am getting
It is some years since I touched CloudKit stuff. I will contact support tomorrow, to get help with my access issue. Everything from my side is just pure speculation so far, as I do not get into my CloudKit dashboard.
I don't really know what you mean by "created for iOS app and not web app". For my knowledge all containers are created through identifiers. Quoting Apple's documentation: "In CloudKit Dashboard, enable web services by creating either an API token or server-to-server key". There is a server-to-server key created and actively used to perform queries.
I do not recall the details. Back then I made the mistake to mix iOS and web connections, as they expect different kind of data, iOS expects binary, web expects JSON.
That's the output I am getting
This shows at least, that the records work in the browser. Do you maybe use the wrong database? Your schema looks like records are supposed to go into the sharedCloudDatabase. Also check the environment. Both client and container have to run either in development or production.
I've checked everything and it all seems fine. Any progress on your side?
I am in contact with support and expect in the coming days some form of solution to access the dashboard again.
Hello, any progress?
Hello @inferutsers,
Sorry for the delay. I got finally access to all necessary parts of CloudKit. So here are my results:
- I was able to reproduce your issue.
- A step in the right direction was to remove all type information from the list object ment to be saved.
- I still got an error, but then it was a regular result with error property that complained about the list structure.
- Considering the fact that it became better after removing type properties, I tried a simple string array, which actually worked.
So the solution for your use case is:
const record: RecordToCreate = { recordType: "TestType", fields: { "testList": list as any } };
Let me know if this is working for you as well. I will fix the typing asap.