jaysonsantos
jaysonsantos•2mo ago

v4 fails to add metadata when using v1 action

Hey there folks, I just updated my self hosted playground to v4, using helm but setting the image version to v4 and it seems that v1 actions are broken. The following code:
const uuid = require("zitadel/uuid");

function addUUID(ctx, api) {
const userMetadata = ctx.v1.user.getMetadata();

// Check if customer_id already exists in metadata
if (userMetadata && userMetadata.metadata) {
for (let i = 0; i < userMetadata.metadata.length; i++) {
if (userMetadata.metadata[i].key === "customer_id") {
return;
}
}
}

api.v1.user.setMetadata("customer_id", uuid.v4());
// api.v1.user.setMetadata(ctx, "customer_id", uuid.v7());
}
const uuid = require("zitadel/uuid");

function addUUID(ctx, api) {
const userMetadata = ctx.v1.user.getMetadata();

// Check if customer_id already exists in metadata
if (userMetadata && userMetadata.metadata) {
for (let i = 0; i < userMetadata.metadata.length; i++) {
if (userMetadata.metadata[i].key === "customer_id") {
return;
}
}
}

api.v1.user.setMetadata("customer_id", uuid.v4());
// api.v1.user.setMetadata(ctx, "customer_id", uuid.v7());
}
Running on pre userinfo creation will fail with the following: (char limit, check thread)
No description
11 Replies
jaysonsantos
jaysonsantosOP•2mo ago
zitadel-79b6fd5dc7-nw7c7 zitadel time="2025-08-04T07:17:24Z" level=info msg=activity caller="/home/runner/work/zitadel/zitadel/internal/activity/activity.go:105" domain="https://zitadel.jayson.com.br" grpcStatus= httpStatus= instance=331323599031895168 isSystemUser=false method= org=331324603248936067 path=/oauth/v2/token requestMethod=POST trigger=accessToken user=331442342999360643
zitadel-79b6fd5dc7-nw7c7 zitadel time="2025-08-04T07:17:24Z" level=info msg="log record emitted" caller="/home/runner/work/zitadel/zitadel/internal/logstore/emitters/stdout/stdout.go:19" record="{\"logDate\":\"2025-08-04T07:17:24.870565417Z\",\"took\":0,\"message\":\"action run started\",\"logLevel\":\"info\",\"instanceId\":\"331323599031895168\"}"
zitadel-79b6fd5dc7-nw7c7 zitadel time="2025-08-04T07:17:24Z" level=info msg="unable to set md in action" caller="/home/runner/work/zitadel/zitadel/internal/api/oidc/userinfo.go:390" error="ID=AUTH-rKLWEH Message=context missing"
zitadel-79b6fd5dc7-nw7c7 zitadel time="2025-08-04T07:17:24Z" level=info msg="log record emitted" caller="/home/runner/work/zitadel/zitadel/internal/logstore/emitters/stdout/stdout.go:19" record="{\"logDate\":\"2025-08-04T07:17:24.874470662Z\",\"took\":3905256,\"message\":\"action run failed: ID=AUTH-rKLWEH Message=context missing\",\"logLevel\":\"error\",\"instanceId\":\"331323599031895168\"}"
zitadel-79b6fd5dc7-nw7c7 zitadel time=2025-08-04T07:17:24.874Z level=WARN msg="request error" oidc_error.parent="ID=AUTH-rKLWEH Message=context missing" oidc_error.description="context missing" oidc_error.type=invalid_request status_code=401
zitadel-79b6fd5dc7-nw7c7 zitadel time="2025-08-04T07:17:24Z" level=info msg=activity caller="/home/runner/work/zitadel/zitadel/internal/activity/activity.go:105" domain="https://zitadel.jayson.com.br" grpcStatus= httpStatus= instance=331323599031895168 isSystemUser=false method= org=331324603248936067 path=/oauth/v2/token requestMethod=POST trigger=accessToken user=331442342999360643
zitadel-79b6fd5dc7-nw7c7 zitadel time="2025-08-04T07:17:24Z" level=info msg="log record emitted" caller="/home/runner/work/zitadel/zitadel/internal/logstore/emitters/stdout/stdout.go:19" record="{\"logDate\":\"2025-08-04T07:17:24.870565417Z\",\"took\":0,\"message\":\"action run started\",\"logLevel\":\"info\",\"instanceId\":\"331323599031895168\"}"
zitadel-79b6fd5dc7-nw7c7 zitadel time="2025-08-04T07:17:24Z" level=info msg="unable to set md in action" caller="/home/runner/work/zitadel/zitadel/internal/api/oidc/userinfo.go:390" error="ID=AUTH-rKLWEH Message=context missing"
zitadel-79b6fd5dc7-nw7c7 zitadel time="2025-08-04T07:17:24Z" level=info msg="log record emitted" caller="/home/runner/work/zitadel/zitadel/internal/logstore/emitters/stdout/stdout.go:19" record="{\"logDate\":\"2025-08-04T07:17:24.874470662Z\",\"took\":3905256,\"message\":\"action run failed: ID=AUTH-rKLWEH Message=context missing\",\"logLevel\":\"error\",\"instanceId\":\"331323599031895168\"}"
zitadel-79b6fd5dc7-nw7c7 zitadel time=2025-08-04T07:17:24.874Z level=WARN msg="request error" oidc_error.parent="ID=AUTH-rKLWEH Message=context missing" oidc_error.description="context missing" oidc_error.type=invalid_request status_code=401
and I made it to fail auth when the function fails because I want to ensure a customer_id is always present *PS don't mind the v7 on UUID, it is there because I sent a PR with it and was testing the code
Rajat
Rajat•2mo ago
hey @jaysonsantos its a known limitation tthat actions are gonna move completely to v2 https://zitadel.com/docs/concepts/features/actions_v2 if you want to test the action you wrote above(all correct btw), run any v3.x.x image or just run a cloud instance (running v3.3.2 atm) and it should work
jaysonsantos
jaysonsantosOP•2mo ago
hey @Rajat got it. the UI says it is still supported, that is why I kept with the same. is there a 1 to 1 event on v2 that can be used with that purpose?
Rajat
Rajat•2mo ago
yes because it IS supported, its only that some of the actions fails because they're migrating to v2(which is when we sill stop working with v1 actions) for 1:1 event, you can check this out https://zitadel.com/docs/guides/integrate/actions/testing-request#create-target bacisally, you need to create a "target" and an "execution" and what happens is whenever that event is "exectuted", it will call the "target"
jaysonsantos
jaysonsantosOP•2mo ago
does this mean that the javascript within zitadel will die?
Ozzzkar
Ozzzkar•2mo ago
I also wanna know cause it's quite nice to have stuff like logging inside Zitadel without needing to call a 3rd party endpoint just to get more information about requests for example. I guess some functionality will stay
jaysonsantos
jaysonsantosOP•2mo ago
true, in terms of functionally, IMHO it is a loss there. my usecase was to assign an uuid v7 on first login but, i guess i'll need to call the api by hand
Rajat
Rajat•2mo ago
hey @jaysonsantos The main shift is that Actions v1 ran js directly within zitadel's environment, with v2 tho, your custom code is now hosted externally, zitadel makes an HTTP POST to your endpoint (Target), sending a JSON payload. But this also means that you can use any language or framework, deploy to your own infra, and take full control over logs/libs/envs, this makes Actions V2 far more adaptable to complex use cases .
Ozzzkar
Ozzzkar•2mo ago
the downside is that you need to set up a framework that receives and responds to zitadel's payloads and that can take some time to get started with, also considering that signing needs to be implemented etc., it's harder to accomplish security-wise. I'm gonna do it in our organization, maybe I'll deploy a sidecar to Zitadel for it
anlumo
anlumo•2mo ago
It might be more adaptable for complex use cases, but it makes everything much harder for simple use cases. Not everything needs a rocket ship when a bicycle will do.
Rajat
Rajat•2mo ago
you are right but in bigger aspects, it gives you full control over languages/libs, you can setup multipule functions/requests/events/responses you can still do a lot of v1 actions in v2 https://zitadel.com/docs/guides/integrate/actions/migrate-from-v1 , give it a try here you can spin up your own server on localhost with ngrok 🙂

Did you find this page helpful?