David Alonso
David Alonso9mo ago

Cryptic undefined is not valid Convex value error

I'm running into this
6/8/2024, 4:12:56 PM [CONVEX M(mutations/blocks/blocks:updateMultipleBlockGridLayouts)] Uncaught Error: undefined is not a valid Convex value (present at path [0] in original object ["undefined","undefined","undefined"]). To learn about Convex's supported types, see https://docs.convex.dev/using/types.
at convexToJsonInternal (../../node_modules/convex/src/values/value.ts:287:6)
at <anonymous> (../../node_modules/convex/src/values/value.ts:322:4)
at map [as map] (<anonymous>)
at convexToJsonInternal (../../node_modules/convex/src/values/value.ts:320:29)
at convexToJson (../../node_modules/convex/src/values/value.ts:417:0)
6/8/2024, 4:12:56 PM [CONVEX M(mutations/blocks/blocks:updateMultipleBlockGridLayouts)] Uncaught Error: undefined is not a valid Convex value (present at path [0] in original object ["undefined","undefined","undefined"]). To learn about Convex's supported types, see https://docs.convex.dev/using/types.
at convexToJsonInternal (../../node_modules/convex/src/values/value.ts:287:6)
at <anonymous> (../../node_modules/convex/src/values/value.ts:322:4)
at map [as map] (<anonymous>)
at convexToJsonInternal (../../node_modules/convex/src/values/value.ts:320:29)
at convexToJson (../../node_modules/convex/src/values/value.ts:417:0)
Have tried adding a bunch of logging statements to catch the undefined values but I can't see where the issue is. I can add console logs up to this point:
return await context.db.patch(block._id, { properties: pageProperties });
return await context.db.patch(block._id, { properties: pageProperties });
10 Replies
David Alonso
David AlonsoOP9mo ago
I'd really appreciate any pointers on what to look for. When I log pageProperties it just looks like a regular object, all values set The mutation looks something like this:
export const updateMultipleBlockGridLayouts = mutation({
args: {
parentBlockId: v.id("blocks"),
gridLayouts: v.array(vGridLayoutItemProps),
},
handler: async (context, args) => {
const { parentBlockId, gridLayouts } = args;
const results = [];
for (const gridLayout of gridLayouts) {
const block = (await context.db
.query("blocks")
.withIndex("by_parent_grid_idx", (q) =>
q
.eq("parentBlockId", parentBlockId)
.eq("properties.gridLayout.i", gridLayout.i as any as undefined)
)
.unique()) as GridBlock;
if (!block)
throw new Error(
`Block not found for parent id: ${parentBlockId} and gridLayout.i: ${gridLayout.i}`
);
const result = await patchBlockPropertiesWithNewGridLayout(
context,
block,
gridLayout
);
results.push(result);
}

return results;
},
});
export const updateMultipleBlockGridLayouts = mutation({
args: {
parentBlockId: v.id("blocks"),
gridLayouts: v.array(vGridLayoutItemProps),
},
handler: async (context, args) => {
const { parentBlockId, gridLayouts } = args;
const results = [];
for (const gridLayout of gridLayouts) {
const block = (await context.db
.query("blocks")
.withIndex("by_parent_grid_idx", (q) =>
q
.eq("parentBlockId", parentBlockId)
.eq("properties.gridLayout.i", gridLayout.i as any as undefined)
)
.unique()) as GridBlock;
if (!block)
throw new Error(
`Block not found for parent id: ${parentBlockId} and gridLayout.i: ${gridLayout.i}`
);
const result = await patchBlockPropertiesWithNewGridLayout(
context,
block,
gridLayout
);
results.push(result);
}

return results;
},
});
And
patchBlockPropertiesWithNewGridLayout
patchBlockPropertiesWithNewGridLayout
I'm able to call from this mutation without issues:
export const updateBlockGridLayoutProps = mutation({
args: { blockId: v.id("blocks"), gridLayout: vGridLayoutItemProps },
handler: async (context, args) => {
const { blockId, gridLayout } = args;
const block = await context.db.get(blockId);
if (!block) throw new Error("Block not found");
return await patchBlockPropertiesWithNewGridLayout(
context,
block,
gridLayout
);
},
});
export const updateBlockGridLayoutProps = mutation({
args: { blockId: v.id("blocks"), gridLayout: vGridLayoutItemProps },
handler: async (context, args) => {
const { blockId, gridLayout } = args;
const block = await context.db.get(blockId);
if (!block) throw new Error("Block not found");
return await patchBlockPropertiesWithNewGridLayout(
context,
block,
gridLayout
);
},
});
lee
lee9mo ago
Can you show the source for patchBlockPropertiesWithNewGridLayout At a guess from the code you have here, there may be cases where it doesn't return any result
David Alonso
David AlonsoOP9mo ago
ah yeah that's true. the code is a little spaghetti so also open to take input on how to make it more concise!
const patchBlockPropertiesWithNewGridLayout = async (
context: MutationCtx,
block: Doc<"blocks">,
gridItemLayout: GridLayoutItemProps
) => {
console.log(`block:`);
console.log(block);
switch (block.type) {
case "page":
const pageProperties: PageBlockProps = {
title: block.properties.title,
isArchived: block.properties.isArchived,
isPublished: block.properties.isPublished,
gridLayout: gridItemLayout,
};
return await context.db.patch(block._id, { properties: pageProperties });
case "table":
const tableProperties: TableBlockProps = {
viewId: block.properties.viewId,
gridLayout: gridItemLayout,
};
return await context.db.patch(block._id, { properties: tableProperties });
case "card":
const cardProperties: CardBlockProps = {
title: block.properties.title,
body: block.properties.body,
gridLayout: gridItemLayout,
};
return await context.db.patch(block._id, { properties: cardProperties });
case "divider":
const dividerProperties: DividerBlockProps = {
type: block.properties.type,
gridLayout: gridItemLayout,
};
return await context.db.patch(block._id, {
properties: dividerProperties,
});
case "heading":
const headingProperties: HeadingBlockProps = {
text: block.properties.text,
gridLayout: gridItemLayout,
};
return await context.db.patch(block._id, {
properties: headingProperties,
});
...
default:
throw new Error(`Unknown block type: ${block.type}`);
}
};
const patchBlockPropertiesWithNewGridLayout = async (
context: MutationCtx,
block: Doc<"blocks">,
gridItemLayout: GridLayoutItemProps
) => {
console.log(`block:`);
console.log(block);
switch (block.type) {
case "page":
const pageProperties: PageBlockProps = {
title: block.properties.title,
isArchived: block.properties.isArchived,
isPublished: block.properties.isPublished,
gridLayout: gridItemLayout,
};
return await context.db.patch(block._id, { properties: pageProperties });
case "table":
const tableProperties: TableBlockProps = {
viewId: block.properties.viewId,
gridLayout: gridItemLayout,
};
return await context.db.patch(block._id, { properties: tableProperties });
case "card":
const cardProperties: CardBlockProps = {
title: block.properties.title,
body: block.properties.body,
gridLayout: gridItemLayout,
};
return await context.db.patch(block._id, { properties: cardProperties });
case "divider":
const dividerProperties: DividerBlockProps = {
type: block.properties.type,
gridLayout: gridItemLayout,
};
return await context.db.patch(block._id, {
properties: dividerProperties,
});
case "heading":
const headingProperties: HeadingBlockProps = {
text: block.properties.text,
gridLayout: gridItemLayout,
};
return await context.db.patch(block._id, {
properties: headingProperties,
});
...
default:
throw new Error(`Unknown block type: ${block.type}`);
}
};
David Alonso
David AlonsoOP9mo ago
okay so I shouldn't do return? not sure where the issue is
lee
lee9mo ago
the issue is patchBlockPropertiesWithNewGridLayout returns undefined, which you store in the results array. And Convex doesn't support return values that have arrays containing undefined. That's what your error message is saying
David Alonso
David AlonsoOP9mo ago
ah now i get it! when i hover over the function definition I saw this which confused me:
const patchBlockPropertiesWithNewGridLayout: (context: MutationCtx, block: Doc<"blocks">, gridItemLayout: GridItemLayoutProps) => Promise<void>
const patchBlockPropertiesWithNewGridLayout: (context: MutationCtx, block: Doc<"blocks">, gridItemLayout: GridItemLayoutProps) => Promise<void>
okay so I guess I should just not return anything from the mutation? not sure what best practice is in this case
lee
lee9mo ago
Best practice is to return what needs to be returned (i.e. what the caller needs). You could return nothing, or return results.length, or convert the undefineds to nulls and return [null, null, null]
David Alonso
David AlonsoOP9mo ago
amazing, it works now! thank you soooo much!!!
Michal Srb
Michal Srb9mo ago
The error message sucks, filing to improve, sorry @David Alonso !

Did you find this page helpful?