Context
I was looking for the code-apps equivalent of the canvas Power Fx DataSourceInfo(dataSource, CreatePermission) (docs). The natural equivalent is the Dataverse functions RetrieveAadUserPrivileges and RetrieveAadUserSetOfPrivilegesByNames, added via npx power-apps add-dataverse-api. Calling the generated services failed — it traced back to a codegen bug in parameter serialization for OData function params.
Environment
@microsoft/power-apps 1.2.5
@microsoft/power-apps-cli 0.12.3
Repro
npx power-apps init -e <envId> -n "repro" -t CodeApp
npx power-apps push # register the app
npx power-apps add-dataverse-api --api-name RetrieveAadUserPrivileges
npx power-apps add-dataverse-api --api-name RetrieveAadUserSetOfPrivilegesByNames
import { getContext } from "@microsoft/power-apps/app";
const { user } = await getContext();
// Bug 1 (Guid):
await RetrieveAadUserPrivilegesService.RetrieveAadUserPrivileges(user.objectId);
// Bug 2 (collection):
await RetrieveAadUserSetOfPrivilegesByNamesService.RetrieveAadUserSetOfPrivilegesByNames(
user.objectId,
["prvCreateAccount"],
);
Actual
RetrieveAadUserPrivileges → 400 0x80060888: "Expression of type 'Edm.String' cannot be converted to type 'Edm.Guid'."
RetrieveAadUserSetOfPrivilegesByNames → 400 0x80060888: "The parameter 'PrivilegeNames=prvCreateAccount' is not in scope."
Expected
Both calls succeed and return the user's privileges (RolePrivileges[]).
Root cause
The generated .power/schemas/appschemas/dataSourcesInfo.ts types:
DirectoryObjectId (CSDL Edm.Guid) → "type": "string"
PrivilegeNames (CSDL Collection(Edm.String)) → "type": "array"
The runtime toODataLiteral(value, type) (@microsoft/power-apps/dist/internal/data/core/data/executors/dataverseDataOperationExecutor.js:680) only special-cases type === 'string' (single-quoting); for everything else it returns String(value). For customapi GET functions, params are assembled into the OData function-call URL FunctionName(p=v,…) at :306-314 with no URL-encoding. Result:
- Guid param (typed
"string") → 'd2290e33-…' (quoted) → Dataverse rejects (string where Guid expected).
- Collection param (typed
"array") → String(["prvCreateAccount"]) = prvCreateAccount (bare token) → Dataverse rejects (not a collection literal).
Workarounds (app-side; both confirmed working)
- Guid — edit
dataSourcesInfo.ts to set the param type to "guid" → toODataLiteral returns the bare GUID → Dataverse accepts.
- Collection — pass
encodeURIComponent(JSON.stringify(["prvCreateAccount"])) as the value → emits a valid encoded OData collection literal → Dataverse accepts.
After both, RetrieveAadUserSetOfPrivilegesByNames(objectId, ["prvCreateAccount"]) returns exactly the matching privilege:
{ "RolePrivileges": [ { "Depth": "Global", "PrivilegeName": "prvCreateAccount", "PrivilegeId": "d26fe964-230b-42dd-ad93-5cc879de411e" } ] }
Suggested fix
- Codegen: map CSDL
Edm.Guid → schema type: "guid" (not "string").
toODataLiteral: handle "guid" (emit bare value) and collection types (emit a JSON array literal, e.g. ["v1","v2"] with each element quoted).
- URL encoding: URL-encode function-param values when building the function-call URL (or use OData alias syntax
@p1 for collections).
- Ensure
add-dataverse-api regenerates dataSourcesInfo.ts so manual patches aren't required.
References
Context
I was looking for the code-apps equivalent of the canvas Power Fx
DataSourceInfo(dataSource, CreatePermission)(docs). The natural equivalent is the Dataverse functionsRetrieveAadUserPrivilegesandRetrieveAadUserSetOfPrivilegesByNames, added vianpx power-apps add-dataverse-api. Calling the generated services failed — it traced back to a codegen bug in parameter serialization for OData function params.Environment
@microsoft/power-apps1.2.5@microsoft/power-apps-cli0.12.3Repro
Actual
RetrieveAadUserPrivileges→400 0x80060888: "Expression of type 'Edm.String' cannot be converted to type 'Edm.Guid'."RetrieveAadUserSetOfPrivilegesByNames→400 0x80060888: "The parameter 'PrivilegeNames=prvCreateAccount' is not in scope."Expected
Both calls succeed and return the user's privileges (
RolePrivileges[]).Root cause
The generated
.power/schemas/appschemas/dataSourcesInfo.tstypes:DirectoryObjectId(CSDLEdm.Guid) →"type": "string"PrivilegeNames(CSDLCollection(Edm.String)) →"type": "array"The runtime
toODataLiteral(value, type)(@microsoft/power-apps/dist/internal/data/core/data/executors/dataverseDataOperationExecutor.js:680) only special-casestype === 'string'(single-quoting); for everything else it returnsString(value). ForcustomapiGET functions, params are assembled into the OData function-call URLFunctionName(p=v,…)at:306-314with no URL-encoding. Result:"string") →'d2290e33-…'(quoted) → Dataverse rejects (string where Guid expected)."array") →String(["prvCreateAccount"])=prvCreateAccount(bare token) → Dataverse rejects (not a collection literal).Workarounds (app-side; both confirmed working)
dataSourcesInfo.tsto set the paramtypeto"guid"→toODataLiteralreturns the bare GUID → Dataverse accepts.encodeURIComponent(JSON.stringify(["prvCreateAccount"]))as the value → emits a valid encoded OData collection literal → Dataverse accepts.After both,
RetrieveAadUserSetOfPrivilegesByNames(objectId, ["prvCreateAccount"])returns exactly the matching privilege:{ "RolePrivileges": [ { "Depth": "Global", "PrivilegeName": "prvCreateAccount", "PrivilegeId": "d26fe964-230b-42dd-ad93-5cc879de411e" } ] }Suggested fix
Edm.Guid→ schematype: "guid"(not"string").toODataLiteral: handle"guid"(emit bare value) and collection types (emit a JSON array literal, e.g.["v1","v2"]with each element quoted).@p1for collections).add-dataverse-apiregeneratesdataSourcesInfo.tsso manual patches aren't required.References
toODataLiteral:node_modules/@microsoft/power-apps/dist/internal/data/core/data/executors/dataverseDataOperationExecutor.js:680customapiparam assembly: same file:276-331DataSourceInfo: https://learn.microsoft.com/en-us/power-platform/power-fx/reference/function-datasourceinfoRetrieveAadUserPrivileges,RetrieveAadUserSetOfPrivilegesByNames(unbound;DirectoryObjectId: Edm.Guid,PrivilegeNames: Collection(Edm.String))