Check existing issues
Bug description
Since the 4.2.1 charmcraft release, one of our charms (kratos-operator) started to fail when packing. Specifically this part:
parts:
schemas:
plugin: dump
source: .
organize:
"claim_mappers/**": schemas/
"identity_schemas/**": schemas/
prime:
- schemas/
It seems that we can't use the same schemas directory for more than one key anymore:
:: 2026-05-28 16:02:05.414 :: + cp --archive --link --no-dereference . /root/parts/schemas/install
:: 2026-05-28 16:02:05.426 Run pre-organize callbacks
:: 2026-05-28 16:02:05.429 Failed to organize part 'schemas': trying to organize 'identity_schemas/**' to 'schemas/', but 'schemas/' already exists.
:: 2026-05-28 16:02:05.438 Traceback (most recent call last):
:: 2026-05-28 16:02:05.438 File "/snap/charmcraft/7759/lib/python3.12/site-packages/craft_application/services/lifecycle.py", line 355, in run
:: 2026-05-28 16:02:05.438 self._exec(actions)
:: 2026-05-28 16:02:05.438 File "/snap/charmcraft/7759/lib/python3.12/site-packages/craft_application/services/lifecycle.py", line 379, in _exec
:: 2026-05-28 16:02:05.438 aex.execute(action, stdout=stream, stderr=stream)
:: 2026-05-28 16:02:05.438 File "/snap/charmcraft/7759/lib/python3.12/site-packages/craft_parts/executor/executor.py", line 353, in execute
:: 2026-05-28 16:02:05.438 self._executor.execute(actions, stdout=stdout, stderr=stderr)
:: 2026-05-28 16:02:05.438 File "/snap/charmcraft/7759/lib/python3.12/site-packages/craft_parts/executor/executor.py", line 153, in execute
:: 2026-05-28 16:02:05.438 self._run_action(act, stdout=stdout, stderr=stderr)
:: 2026-05-28 16:02:05.438 File "/snap/charmcraft/7759/lib/python3.12/site-packages/craft_parts/executor/executor.py", line 246, in _run_action
:: 2026-05-28 16:02:05.438 handler.run_action(action, stdout=stdout, stderr=stderr)
:: 2026-05-28 16:02:05.439 File "/snap/charmcraft/7759/lib/python3.12/site-packages/craft_parts/executor/part_handler.py", line 313, in run_action
:: 2026-05-28 16:02:05.439 state = handler(step_info, stdout=stdout, stderr=stderr)
:: 2026-05-28 16:02:05.439 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
:: 2026-05-28 16:02:05.439 File "/snap/charmcraft/7759/lib/python3.12/site-packages/craft_parts/executor/part_handler.py", line 487, in _run_build
:: 2026-05-28 16:02:05.439 organize_files(
:: 2026-05-28 16:02:05.439 File "/snap/charmcraft/7759/lib/python3.12/site-packages/craft_parts/executor/organize.py", line 129, in organize_files
:: 2026-05-28 16:02:05.439 raise errors.FileOrganizeError(
:: 2026-05-28 16:02:05.439 craft_parts.errors.FileOrganizeError: Failed to organize part 'schemas': trying to organize 'identity_schemas/**' to 'schemas/', but 'schemas/' already exists.
The charm was packing fine with 4.0.1.
With 4.2.1, it is packed successfully once switched to "claim_mappers/**": schemas/claim_mappers "identity_schemas/**": schemas/identity_schemas (distinct subdirectories) but I'm wondering if this was intentional.
Steps to reproduce
git clone https://github.com/canonical/kratos-operator.git && cd kratos-operator
charmcraft pack -v
Environment
ubuntu 24.04
charmcraft.yaml
# Copyright 2025 Canonical Ltd.
# See LICENSE file for licensing details.
name: kratos
type: charm
description: |
Charmed Ory Kratos
summary: |
Identity and user management system
links:
documentation: https://canonical-identity.readthedocs-hosted.com/reference/charms/kratos
source: https://github.com/canonical/kratos-operator
issues: https://github.com/canonical/kratos-operator/issues
containers:
kratos:
resource: oci-image
resources:
oci-image:
type: oci-image
description: Kratos oci-image
upstream-source: ghcr.io/canonical/kratos:25.4.0
verification-email-template:
type: file
filename: verification-email-template.gotmpl
description: Custom email verification template to use with code method
requires:
pg-database:
interface: postgresql_client
optional: false
kratos-external-idp:
interface: external_provider
optional: true
hydra-endpoint-info:
interface: hydra_endpoints
limit: 1
optional: true
ui-endpoint-info:
interface: login_ui_endpoints
optional: true
kratos-registration-webhook:
interface: kratos_registration_webhook
optional: true
kratos-login-webhook:
interface: kratos_login_webhook
optional: true
logging:
interface: loki_push_api
optional: true
tracing:
interface: tracing
limit: 1
optional: true
description: |
Provides traces to COS Tempo instance
smtp:
interface: smtp
limit: 1
optional: true
internal-route:
interface: traefik_route
limit: 1
optional: true
description: |
Ingress used for cross-cluster communication where network topology is more complex
than just one k8s cluster
public-route:
interface: traefik_route
optional: true
description: |
Recommended way to expose the charm to the public internet
receive-ca-cert:
interface: certificate_transfer
optional: true
description: |
Receive a CA cert.
This relation can be used with a local CA to obtain the CA cert that was used to sign proxied
endpoints.
peers:
kratos-peers:
interface: kratos-peers
provides:
kratos-info:
interface: kratos_info
description: |
Provides kratos deployment info to a related application
optional: true
metrics-endpoint:
interface: prometheus_scrape
description: |
Provides application metrics to COS Prometheus instance
optional: true
grafana-dashboard:
description: |
Forwards the built-in grafana dashboard(s) for monitoring kratos.
interface: grafana_dashboard
optional: true
config:
options:
http_proxy:
description: URL of the HTTP proxy eg http://proxy.internal:6666, it will set the HTTP_PROXY var in the workload environment
type: string
default: ''
https_proxy:
description: URL of the HTTPS proxy eg http://proxy.internal:6666, it will set the HTTPS_PROXY var in the workload environment
type: string
default: ''
no_proxy:
description: Domains that need to be excluded from proxying no_proxy="test.com,test.co.uk", it is a comma separate list
type: string
default: ''
cpu:
description: |
K8s cpu resource limit, e.g. "1" or "500m". Default is unset (no limit). This value is used
for the "limits" portion of the resource requirements (the "requests" portion is
automatically deduced from it).
See https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/
type: string
memory:
description: |
K8s memory resource limit, e.g. "1Gi". Default is unset (no limit). This value is used
for the "limits" portion of the resource requirements (the "requests" portion is
automatically deduced from it).
See https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/
type: string
dev:
description: Run Kratos on dev mode, it is needed if HTTPS is not set up. This should only be used for development purposes.
type: boolean
default: False
enable_local_idp:
description: Enable Kratos Identity Provider
type: boolean
default: True
enforce_mfa:
description: |
Enforce users to set up and use multi factor authentication.
Disabling this option will allow users to log in with password or webauthn without completing 2fa.
type: boolean
default: True
enable_verification:
description: |
Enable and enforce users to verify their accounts.
Enabling this option will make users verify their accounts after registration or on the next login.
This option requires an SMTP server integration.
type: boolean
default: False
sender_email:
description: |
The email address used as the sender for automated verification and recovery emails.
type: string
default: "identity@canonical.com"
sender_name:
description: |
The display name that appears alongside the sender email address in recovery and verification emails.
type: string
default: "Canonical Identity Platform"
enable_passwordless_login_method:
description: |
Enable passwordless authentication via webauthn. Requires `enable_local_idp=True`.
type: boolean
default: False
enable_oidc_webauthn_sequencing:
description: |
Enforce setting up a WebAuthn key (e.g. with YubiKey or Google Password Manager on Android)
after signing in with an external identity provider. Requires `enable_passwordless_login_method=False`.
WARNING: Do not enable this option unless you are sure that this feature applies to your deployment.
type: boolean
default: False
identity_schemas:
description: |
A mapping of schema_id to identity schemas. For example:
{
"user_v0": {
"$id": "https://schemas.ory.sh/presets/kratos/quickstart/email-password/identity.schema.json",
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "Person",
"type": "object",
"properties": {
"traits": {
"type": "object",
"properties": {
"email": {
"type": "string",
"format": "email",
"title": "E-Mail",
"minLength": 3,
"ory.sh/kratos": {
"verification": {
"via": "email"
}
}
},
"name": {
"type": "string"
}
}
},
"additionalProperties": true
}
}
}
type: string
default_identity_schema_id:
description: The default identity schema id, this option only works when `identity_schemas` is defined
type: string
recovery_email_template:
description: |
The custom html template used to send emails with recovery codes. For example:
Hi,
Please enter the following code to recover your account:
{{ .RecoveryCode }}
type: string
log_level:
description: |
The verbosity of logs produced by Kratos.
Available values are: panic, fatal, error, warn, info, debug, and trace.
type: string
default: "info"
actions:
get-identity:
description: Get a user using either the identity ID or the user email.
params:
identity-id:
description: The Identity ID
type: string
email:
description: The user's email
type: string
delete-identity:
description: Delete a user using the identity ID or the user email.
params:
identity-id:
description: The Identity ID
type: string
email:
description: The user's email
type: string
create-admin-account:
description: |
Create an admin user. If no password was provided, the command will return a
magic link where the user will be able to set their password.
params:
username:
description: The admin username
type: string
email:
description: |
The admin's email, this email must not be associated with any other account
(user or admin)
type: string
password-secret-id:
description: The juju secret that contains the admin's password
type: string
name:
description: The admin's name
type: string
phone-number:
description: The admin's phone number
type: string
required:
- username
- email
reset-password:
description: |
Reset password of an identity using the identity ID or the user email.
params:
identity-id:
description: The Identity ID
type: string
email:
description: The user's email
type: string
password-secret-id:
description: |
The juju secret that contains the password to set for an identity. If
not provided, a self-service recovery link will be returned.
type: string
invalidate-identity-sessions:
description: |
Invalidate all user sessions using the identity ID or the user email.
params:
identity-id:
description: The Identity ID
type: string
email:
description: The user's email
type: string
reset-identity-mfa:
description: |
Reset identity's second authentication factor using the identity ID or the user email.
params:
identity-id:
description: The Identity ID
type: string
email:
description: The user's email
type: string
mfa-type:
description: The type of credentials to be removed, one of `totp`, `lookup_secret` or `webauthn`.
type: string
enum:
- totp
- lookup_secret
- webauthn
required:
- mfa-type
list-oidc-accounts:
description: |
Retrieve the list of OIDC accounts identifiers linked to an identity using the identity ID or the user email.
params:
identity-id:
description: The Identity ID
type: string
email:
description: The user's email
type: string
unlink-oidc-account:
description: |
Unlink a user's external identity provider account from their identity using the identity ID or the user email.
params:
identity-id:
description: The Identity ID
type: string
email:
description: The user's email
type: string
credential-id:
description: The OIDC credential ID to unlink. Run `list-identity-linked-oidc-accounts` to list available credentials.
type: string
required:
- credential-id
run-migration:
description: |
Run a migration, this is needed after upgrades. This is a non-reversible operation.
Run this after backing up the database.
params:
timeout:
description: Timeout after which the migration will be canceled
type: number
default: 120
########################### build ###########################
platforms:
ubuntu@22.04:amd64:
parts:
schemas:
plugin: dump
source: .
organize:
"claim_mappers/**": schemas/
"identity_schemas/**": schemas/
prime:
- schemas/
charm:
charm-binary-python-packages:
- jsonschema
- bcrypt
- "setuptools>=70.0.0"
build-packages:
- "rustc-1.85"
- "cargo-1.85"
Log output
Check existing issues
Bug description
Since the 4.2.1 charmcraft release, one of our charms (kratos-operator) started to fail when packing. Specifically this part:
It seems that we can't use the same schemas directory for more than one key anymore:
The charm was packing fine with 4.0.1.
With 4.2.1, it is packed successfully once switched to
"claim_mappers/**": schemas/claim_mappers "identity_schemas/**": schemas/identity_schemas(distinct subdirectories) but I'm wondering if this was intentional.Steps to reproduce
git clone https://github.com/canonical/kratos-operator.git && cd kratos-operator
charmcraft pack -v
Environment
ubuntu 24.04
charmcraft.yaml
Log output