{"record":{"id":"5fd753f087d85eac","repo":"usememos/memos","slug":"uid-is-invalid","errorCode":null,"errorMessage":"uid is invalid","messagePattern":"uid is invalid","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"store/deployment_config.go","lineNumber":163,"sourceCode":"\t}\n\tif len(content) > maxDeploymentConfigurationSize {\n\t\treturn errors.Errorf(\"file exceeds %d bytes\", maxDeploymentConfigurationSize)\n\t}\n\tif err := (protojson.UnmarshalOptions{DiscardUnknown: false}).Unmarshal(content, message); err != nil {\n\t\tif matches := protoJSONUnknownFieldMatcher.FindStringSubmatch(err.Error()); len(matches) == 2 {\n\t\t\treturn errors.Errorf(\"failed to decode protobuf JSON: unknown field %q\", matches[1])\n\t\t}\n\t\treturn errors.New(\"failed to decode protobuf JSON; verify field names, value types, and JSON syntax\")\n\t}\n\treturn nil\n}\n\nfunc validateDeploymentIdentityProvider(provider *storepb.IdentityProvider) error {\n\tif provider.Id != 0 {\n\t\treturn errors.New(\"id must be omitted\")\n\t}\n\tif !base.UIDMatcher.MatchString(provider.Uid) {\n\t\treturn errors.New(\"uid is invalid\")\n\t}\n\tif strings.TrimSpace(provider.Name) == \"\" {\n\t\treturn errors.New(\"name is required\")\n\t}\n\tif provider.Type != storepb.IdentityProvider_OAUTH2 {\n\t\treturn errors.New(\"type must be OAUTH2\")\n\t}\n\tif provider.IdentifierFilter != \"\" {\n\t\tif _, err := regexp.Compile(provider.IdentifierFilter); err != nil {\n\t\t\treturn errors.Wrap(err, \"identifierFilter must be a valid regular expression\")\n\t\t}\n\t}\n\tconfig := provider.Config.GetOauth2Config()\n\tif config == nil {\n\t\treturn errors.New(\"config.oauth2Config is required\")\n\t}\n\trequired := []struct {\n\t\tname  string","sourceCodeStart":145,"sourceCodeEnd":181,"githubUrl":"https://github.com/usememos/memos/blob/14d757ce1fb31c78590f374bc042f8dbedbc20d7/store/deployment_config.go#L145-L181","documentation":"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.","triggerScenarios":"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\").","commonSituations":"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.","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-]."],"exampleFix":"// before (memos-idp-github.json)\n{ \"uid\": \"my_github.idp\", \"name\": \"GitHub\", \"type\": \"OAUTH2\", ... }\n\n// after\n{ \"uid\": \"github-oauth\", \"name\": \"GitHub\", \"type\": \"OAUTH2\", ... }","handlingStrategy":"validation","validationCode":"// Go: validate before writing the deployment file\nvar uidMatcher = regexp.MustCompile(`^[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,34}[a-zA-Z0-9])?$`)\nif !uidMatcher.MatchString(provider.Uid) {\n    return fmt.Errorf(\"idp uid %q must be 1-36 chars of [a-zA-Z0-9-], starting/ending alphanumeric\", provider.Uid)\n}","typeGuard":"func isValidUID(uid string) bool {\n    return regexp.MustCompile(`^[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,34}[a-zA-Z0-9])?$`).MatchString(uid)\n}","tryCatchPattern":null,"preventionTips":["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."],"tags":["configuration","validation","identity-provider","startup"],"backgroundTag":null,"analyzedSha":"14d757ce1fb31c78590f374bc042f8dbedbc20d7","analyzedAt":"2026-08-15T09:27:36.538Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}