usememos/memos · error
uid is invalid
Error message
uid is invalid
What it means
Thrown while validating an identity-provider deployment file (memos-idp-*.json in /etc/secrets) when the 'uid' field does not match the base UID pattern ^[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,34}[a-zA-Z0-9])?$ (1-36 chars, starts and ends with a letter or digit, only letters/digits/dashes inside). It is a fail-fast startup check: LoadDeploymentConfigurationDir returns this error wrapped as 'invalid identity provider deployment file', so the server refuses to start with a malformed IdP file.
Source
Thrown at store/deployment_config.go:163
}
if len(content) > maxDeploymentConfigurationSize {
return errors.Errorf("file exceeds %d bytes", maxDeploymentConfigurationSize)
}
if err := (protojson.UnmarshalOptions{DiscardUnknown: false}).Unmarshal(content, message); err != nil {
if matches := protoJSONUnknownFieldMatcher.FindStringSubmatch(err.Error()); len(matches) == 2 {
return errors.Errorf("failed to decode protobuf JSON: unknown field %q", matches[1])
}
return errors.New("failed to decode protobuf JSON; verify field names, value types, and JSON syntax")
}
return nil
}
func validateDeploymentIdentityProvider(provider *storepb.IdentityProvider) error {
if provider.Id != 0 {
return errors.New("id must be omitted")
}
if !base.UIDMatcher.MatchString(provider.Uid) {
return errors.New("uid is invalid")
}
if strings.TrimSpace(provider.Name) == "" {
return errors.New("name is required")
}
if provider.Type != storepb.IdentityProvider_OAUTH2 {
return errors.New("type must be OAUTH2")
}
if provider.IdentifierFilter != "" {
if _, err := regexp.Compile(provider.IdentifierFilter); err != nil {
return errors.Wrap(err, "identifierFilter must be a valid regular expression")
}
}
config := provider.Config.GetOauth2Config()
if config == nil {
return errors.New("config.oauth2Config is required")
}
required := []struct {
name stringView on GitHub (pinned to 14d757ce1f)
Solutions
- Set "uid" in the memos-idp-*.json file to a short slug of letters, digits and dashes (e.g. "github-oauth"), 1-36 characters, starting and ending with a letter or digit.
- Match the uid to the filename suffix (memos-idp-<uid>.json) so file and payload stay consistent.
- Remove any underscore/dot characters; the matcher only allows [a-zA-Z0-9-].
Example fix
// before (memos-idp-github.json)
{ "uid": "my_github.idp", "name": "GitHub", "type": "OAUTH2", ... }
// after
{ "uid": "github-oauth", "name": "GitHub", "type": "OAUTH2", ... } Defensive patterns
Strategy: validation
Validate before calling
// Go: validate before writing the deployment file
var uidMatcher = regexp.MustCompile(`^[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,34}[a-zA-Z0-9])?$`)
if !uidMatcher.MatchString(provider.Uid) {
return fmt.Errorf("idp uid %q must be 1-36 chars of [a-zA-Z0-9-], starting/ending alphanumeric", provider.Uid)
} Type guard
func isValidUID(uid string) bool {
return regexp.MustCompile(`^[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,34}[a-zA-Z0-9])?$`).MatchString(uid)
} Prevention
- Adopt a naming convention for IdP files: memos-idp-<uid>.json where <uid> is already slug-form.
- Lint deployment JSON in CI with a JSON-schema derived from the proto before it reaches /etc/secrets.
When it happens
Trigger: A memos-idp-<something>.json file whose "uid" is missing (empty string), contains underscores, dots, spaces or unicode, is longer than 36 characters, or starts/ends with a dash (e.g. "my_idp", "-idp-", "My.CustomProvider").
Common situations: Migrating from an older bootstrap that wrote IdPs into the database with a freer uid format; copy-pasting an OAuth client id with dots as the uid; renaming files but forgetting to update the uid field inside.
Related errors
- name is required
- type must be OAUTH2
- config.oauth2Config is required
- config.oauth2Config.scopes is required
- config.oauth2Config.fieldMapping.identifier is required
AI-assisted analysis of usememos/memos@14d757ce1f (2026-08-15).
Data as JSON: /api/errors/5fd753f087d85eac.
Report an issue: GitHub.