Hi there,
Overview
I’m trying to programmatically create a new file inside of penpot and add an svg inside of that file. I’ve confirmed the file gets created, however, when it tries to insert the svg, I’m getting a 500 response with “invalid shape found after applying changes.” I’ve tried:
- Changing
"frame-id"
/"parent-id"
to something else, e.g. leaving them out or setting them to the same ID as the shape itself - Removing
"shapes": ["516c04a1-8325-40a4-927a-e5c9bbf2335f"]
from the root frame object - Checking whether the shape might need to reference an existing “root shape” ID if that’s how Penpot handles top-level frames
- Confirming the user’s cookie is valid (the
create-file
call does succeed, so presumably it’s recognized?)
But so far, I keep triggering the same 500. Is there a specific shape property, parent reference, or child reference that’s causing this shape validation to fail? Or is it something else? From the logs, I see that Penpot is complaining about my “Root Frame” object.
Full Context
I’m building a web app with a penpot instance sitting inside of it. I have two apps running locally:
- My main app at localhost:3000
- Penpot (from source) at localhost:3449
My main app is making an HTTP request to Penpot’s backend (/api/rpc/command/update-file
) to:
- Create a new file via
create-file
- Insert a top-level
frame
shape called"Root Frame"
- Insert an
svg-raw
shape inside that new frame, containing some test SVG
Auth is done by reusing the user’s existing Penpot session cookie. In my logs, I see the cookie like: auth-token=eyJhbGciOiJBMjU2S1ciLCJlbmMiOiJBMjU2R0NNIn0.lGCGi…
My code to do this is in a route handler (route.ts
) under the following function:
// …
async function createFileAndPasteTextInPenpot(snippetHtml: string, userCookie: string): Promise {
// 1) create-file
// 2) parse the newly created file’s ID and page ID
// 3) update-file with two “add-obj” changes:
// (a) A top-level “frame” shape
// (b) An “svg-raw” shape as a child of that frame
}
// …
I can confirm the “create-file” call succeeds (I see a new file ID and page ID in the logs). The next call to update-file
fails with status 500. The terminal shows a large “invalid shape found” error from Penpot.
When I run this, I see the following in the logs:
“invalid shape found after applying changes”
…
“Shape geometry is invalid”
or
“Shape minimal record” …
along with a big chunk of shape schema checks. In the logs, it references the “Root Frame” shape with:
points = [[0, 0], [1200, 0], [1200, 800], [0, 800]]
parent-id = “00000000-0000-0000-0000-000000000000”
frame-id = “00000000-0000-0000-0000-000000000000”
shapes = [“516c04a1-8325-40a4-927a-e5c9bbf2335f”]
But that child shape "516c04a1-8325-40a4-927a-e5c9bbf2335f"
is never declared as an add-obj
. So maybe that’s part of the issue. Or maybe it’s that the root frame’s parent is 00000000-0000-0000-0000-000000000000
when it shouldn’t be. I’m not sure which detail is causing the validation to fail. Here are the logs:
[DEBUG] Entering createFileAndPasteTextInPenpot() function…
[DEBUG] userCookie (session cookie) value: auth-token=eyJhbGciOiJBMjU2S1ciL…
[DEBUG] Attempting to create-file in Penpot at http://localhost:3449
[DEBUG] createdFileData from Penpot create-file: {
‘~:features’: {
‘~#set’: [
‘layout/grid’,
‘fdata/pointer-map’,
‘fdata/objects-map’,
‘components/v2’,
‘fdata/shape-data-type’
]
},
‘~:name’: ‘AI Created File’,
‘~:revn’: 0,
‘~:vern’: 0,
‘~:id’: ‘~u5b16e598-5edb-8033-8005-a8868825e561’,
‘~:is-shared’: false,
‘~:version’: 61,
‘~:project-id’: ‘~u5b16e598-5edb-8033-8005-a5ea9f9ce5c6’,
‘~:data’: {
‘~:pages’: [ ‘~u5b16e598-5edb-8033-8005-a8868826392a’ ],
‘~:pages-index’: { ‘~u5b16e598-5edb-8033-8005-a8868826392a’: [Object] },
‘~:id’: ‘~u5b16e598-5edb-8033-8005-a8868825e561’,
‘~:options’: { ‘~:components-v2’: true }
}
}
[DEBUG] New file ID: ~u5b16e598-5edb-8033-8005-a8868825e561 => 5b16e598-5edb-8033-8005-a8868825e561 revn: 0
[DEBUG] Found page ID: ~u5b16e598-5edb-8033-8005-a8868826392a => 5b16e598-5edb-8033-8005-a8868826392a
[DEBUG] No root frame ID found for page. We’ll create a brand-new one ourselves…
[DEBUG] Next step: Attempting to call update-file to insert a root ‘frame’ plus an ‘svg-raw’ shape…
[DEBUG] updateFileBody: {
id: ‘5b16e598-5edb-8033-8005-a8868825e561’,
‘session-id’: ‘f68de4c4-8ca3-4a08-ac60-20b60ecd9d86’,
revn: 0,
vern: 0,
changes: [
{
type: ‘add-obj’,
id: ‘0674c97c-43a6-441d-88fb-c50673a88ea3’,
‘page-id’: ‘5b16e598-5edb-8033-8005-a8868826392a’,
‘frame-id’: ‘00000000-0000-0000-0000-000000000000’,
obj: [Object]
},
{
type: ‘add-obj’,
id: ‘870d47cd-5519-4fb9-ace4-ca972322b4a9’,
‘page-id’: ‘5b16e598-5edb-8033-8005-a8868826392a’,
‘frame-id’: ‘ca8889ee-8827-4717-a62e-e2e7797b3e35’,
obj: [Object]
}
]
}
[DEBUG] Attempting fetch to http://localhost:3449/api/rpc/command/update-file
[DEBUG] update-file responded with status: 500
[DEBUG] update-file failed. Response text: {“~:type”:“~:server-error”,“~:code”:“~:assertion”,“~:hint”:“invalid shape found after applying changes”,“~:explain”:“Errors:\n[{:path [0], … (massive schema validation error) …}]\n\nValue:\n{:y 0,\n :hide-fill-on-export false,\n :transform [1 0 0 1 0 0],\n :hide-in-viewer false,\n :name "Root Frame",\n :width 1200,\n :type "frame",\n :points [[0 0] [1200 0] [1200 800] [0 800]],\n :show-content true,\n :transform-inverse [1 0 0 1 0 0],\n :page-id "5b16e598-5edb-8033-8005-a8868826392a",\n :id #uuid "0674c97c-43a6-441d-88fb-c50673a88ea3",\n …}\n\n”}
[DEBUG] This indicates invalid session/cookie or shape validation errors, etc.
Below is the gist of my “update-file” body that fails. After the POST
to /api/rpc/command/update-file
, Penpot returns a 500 with the big “invalid shape found” schema error.
{
“id”: “5b16e598-5edb-8033-8005-a8868825e561”,
“session-id”: “f68de4c4-8ca3-4a08-ac60-20b60ecd9d86”,
“revn”: 0,
“vern”: 0,
“changes”: [
{
“type”: “add-obj”,
“id”: “0674c97c-43a6-441d-88fb-c50673a88ea3”,
“page-id”: “5b16e598-5edb-8033-8005-a8868826392a”,
“frame-id”: “00000000-0000-0000-0000-000000000000”,
“obj”: {
“id”: “0674c97c-43a6-441d-88fb-c50673a88ea3”,
“type”: “frame”,
“name”: “Root Frame”,
“page-id”: “5b16e598-5edb-8033-8005-a8868826392a”,
“parent-id”: “00000000-0000-0000-0000-000000000000”,
“frame-id”: “00000000-0000-0000-0000-000000000000”,
“points”: [[0, 0], [1200, 0], [1200, 800], [0, 800]],
“x”: 0,
“y”: 0,
“width”: 1200,
“height”: 800,
“selrect”: { “x”: 0, “y”: 0, “width”: 1200, “height”: 800 },
“transform”: [1, 0, 0, 1, 0, 0],
“transform-inverse”: [1, 0, 0, 1, 0, 0],
“shapes”: [“516c04a1-8325-40a4-927a-e5c9bbf2335f”],
“hide-fill-on-export”: false,
“hide-in-viewer”: false,
“show-content”: true
}
},
{
“type”: “add-obj”,
“id”: “870d47cd-5519-4fb9-ace4-ca972322b4a9”,
“page-id”: “5b16e598-5edb-8033-8005-a8868826392a”,
“frame-id”: “ca8889ee-8827-4717-a62e-e2e7797b3e35”,
“obj”: {
“id”: “870d47cd-5519-4fb9-ace4-ca972322b4a9”,
“type”: “svg-raw”,
“name”: “Simple UI (raw SVG)”,
“page-id”: “5b16e598-5edb-8033-8005-a8868826392a”,
“parent-id”: “0674c97c-43a6-441d-88fb-c50673a88ea3”,
“frame-id”: “0674c97c-43a6-441d-88fb-c50673a88ea3”,
“points”: [[80, 80], [480, 80], [480, 380], [80, 380]],
“x”: 80,
“y”: 80,
“width”: 400,
“height”: 300,
“selrect”: { “x”: 80, “y”: 80, “width”: 400, “height”: 300 },
“transform”: [1, 0, 0, 1, 0, 0],
“transform-inverse”: [1, 0, 0, 1, 0, 0],
“svg-attrs”: {
“raw”: “<svg …> … ”
}
}
}
]
}
Appreciate the help,
Rohan