I’ve looked for this error in the community and I can’t find why I keep getting it. I’m building a Jira app with Forge Custom UI and I’m trying to store and retrieve some data for the app. The error I’m getting is:
Error invoking save-view: Error: There was an error invoking the function - Provided request body is invalid
at invoke (https://jira-frontend-bifrost.prod-east.frontend.public.atl-paas.net/assets/async-forge-ui-full-page-extension.23b6c6b5.js:82:46361)
at async https://jira-frontend-bifrost.prod-east.frontend.public.atl-paas.net/assets/async-forge-ui-full-page-extension.23b6c6b5.js:82:79730
Error: There was an error invoking the function - Provided request body is invalid
at he.error (https://forge.cdn.prod.atlassian-dev.net/global-bridge.js:2:131452)
at Object.<anonymous> (https://forge.cdn.prod.atlassian-dev.net/global-bridge.js:2:139225)
at JSON.parse (<anonymous>)
at Oe.o (https://forge.cdn.prod.atlassian-dev.net/global-bridge.js:2:139084)
at Oe (https://forge.cdn.prod.atlassian-dev.net/global-bridge.js:2:139237)
at Te.s.on (https://forge.cdn.prod.atlassian-dev.net/global-bridge.js:2:143897)
at Te (https://forge.cdn.prod.atlassian-dev.net/global-bridge.js:2:144034)
at https://forge.cdn.prod.atlassian-dev.net/global-bridge.js:2:150020
at e.try (https://forge.cdn.prod.atlassian-dev.net/global-bridge.js:2:122504)
at https://forge.cdn.prod.atlassian-dev.net/global-bridge.js:2:149817
Then the frontend portion where the save and read functions are called is:
const loadViews = async () => {
console.log("Loading views from storage...");
const savedViews = await invoke('load-views');
console.log("Loaded views:", savedViews);
return savedViews || [];
};
const handleSaveView = async (viewName) => {
console.log("handleSaveView called with name:", viewName);
const viewConfiguration = {
projectOrder: projectData.map(p => p.key),
milestoneSelection: milestoneSelection
};
try {
await invoke('save-view', { viewName, viewConfiguration: JSON.stringify(viewConfiguration) });
} catch (e) {
console.error("Error invoking save-view:", e);
}
loadViews().then(savedViews => {
setViews(savedViews);
});
setSelectedView(viewName);
setIsSaveViewModalOpen(false);
};
And here’s the portion of the backend implementation:
import Resolver from '@forge/resolver';
import api, { route } from '@forge/api';
import { kvs } from '@forge/kvs';
resolver.define('load-views', async () => {
console.log("Loading views from storage (backend)...");
const savedViews = await kvs.entity('roadmap-views').get('all-views');
console.log("Loaded views (backend):", savedViews);
return savedViews || [];
});
resolver.define('save-view', async ({ payload }) => {
const { viewName, viewConfiguration } = payload;
const parsedConfiguration = JSON.parse(viewConfiguration);
console.log("Saving view configuration (backend):", viewName);
// Get existing views
let allViews = await kvs.entity('roadmap-views').get('all-views');
if (!allViews) {
allViews = [];
}
// Add or update the view
const newView = { name: viewName, configuration: parsedConfiguration };
const existingViewIndex = allViews.findIndex(v => v.name === viewName);
if (existingViewIndex > -1) {
allViews[existingViewIndex] = newView;
} else {
allViews.push(newView);
}
// Save the updated list of views
await kvs.entity('roadmap-views').set('all-views', allViews);
return { success: true };
});
Could someone help me to point me to what I’m doing wrong? I’m not sure if the payload is not properly shared to the backend, or if the data is not formated correctly