{"record":{"id":"4751977f809bb9c2","repo":"AlistGo/alist","slug":"share-id-must-be-1-32-characters-of-letters-numbe","errorCode":null,"errorMessage":"share_id must be 1-32 characters of letters, numbers, underscore or hyphen","messagePattern":"share_id must be 1-32 characters of letters, numbers, underscore or hyphen","errorType":"validation","errorClass":null,"httpStatus":400,"severity":"warning","filePath":"server/handles/share.go","lineNumber":30,"sourceCode":"\t\"time\"\n\n\t\"github.com/alist-org/alist/v3/internal/db\"\n\tshareauth \"github.com/alist-org/alist/v3/internal/share\"\n\n\t\"github.com/alist-org/alist/v3/internal/fs\"\n\t\"github.com/alist-org/alist/v3/internal/model\"\n\t\"github.com/alist-org/alist/v3/pkg/utils\"\n\t\"github.com/alist-org/alist/v3/pkg/utils/random\"\n\t\"github.com/alist-org/alist/v3/server/common\"\n\t\"github.com/gin-gonic/gin\"\n)\n\nconst shareAccessTokenLifetime = 24 * time.Hour\n\nvar shareIDPattern = regexp.MustCompile(`^[A-Za-z0-9_-]{1,32}$`)\n\nvar (\n\terrShareIDInvalid = errors.New(\"share_id must be 1-32 characters of letters, numbers, underscore or hyphen\")\n\terrShareIDExists  = errors.New(\"share link already exists\")\n)\n\ntype CreateShareReq struct {\n\tPath          string `json:\"path\" binding:\"required\"`\n\tShareID       string `json:\"share_id\"`\n\tName          string `json:\"name\"`\n\tPassword      string `json:\"password\"`\n\tExpireAt      string `json:\"expire_at\"`\n\tExpireHours   int64  `json:\"expire_hours\"`\n\tAccessLimit   int64  `json:\"access_limit\"`\n\tBurnAfterRead *bool  `json:\"burn_after_read\"`\n\tAllowPreview  *bool  `json:\"allow_preview\"`\n\tAllowDownload *bool  `json:\"allow_download\"`\n}\n\ntype UpdateShareReq struct {\n\tShareID       string  `json:\"share_id\" binding:\"required\"`","sourceCodeStart":12,"sourceCodeEnd":48,"githubUrl":"https://github.com/AlistGo/alist/blob/843d9dc8149126976b2625911e45a4d3ffd6f2f5/server/handles/share.go#L12-L48","documentation":"errShareIDInvalid is returned by the share-creation endpoint when a client-supplied share_id fails the regex ^[A-Za-z0-9_-]{1,32}$. Custom share IDs are the URL slug of the share link, so they are restricted to URL-safe characters and a 32-character maximum. The error is predeclared alongside errShareIDExists and validated against shareIDPattern before any DB write.","triggerScenarios":"POST to the share-create endpoint with share_id containing spaces, dots, slashes, CJK characters, or any symbol outside letters/digits/underscore/hyphen; or a share_id longer than 32 characters.","commonSituations":"Users typing a descriptive slug like 'my holiday photos!' or pasting a full path '/share/holiday'; generating IDs from filenames with unicode; length overflow when deriving the ID from a hash.","solutions":["Use 1-32 characters of A-Z, a-z, 0-9, '_' or '-' only (e.g. 'holiday-2026')","Or omit share_id entirely and let the server generate a random one","Client-side: validate with the same regex before submitting"],"exampleFix":"// before\n{\"path\": \"/photos\", \"share_id\": \"my holiday photos!\"}\n// after\n{\"path\": \"/photos\", \"share_id\": \"my-holiday-photos\"}","handlingStrategy":"validation","validationCode":"var shareIDPattern = regexp.MustCompile(`^[A-Za-z0-9_-]{1,32}$`)\nif req.ShareID != \"\" && !shareIDPattern.MatchString(req.ShareID) {\n    return errors.New(\"share_id must match [A-Za-z0-9_-]{1,32}\")\n}","typeGuard":"func isValidShareID(id string) bool {\n    return shareIDPattern.MatchString(id) // ^[A-Za-z0-9_-]{1,32}$\n}","tryCatchPattern":null,"preventionTips":["Validate share IDs client-side with the same regex before submission","Slugify user-provided share IDs (spaces->hyphens, strip other symbols)","Leave share_id empty to get a server-generated random ID"],"tags":["share","http-api","validation","slug"],"backgroundTag":null,"analyzedSha":"843d9dc8149126976b2625911e45a4d3ffd6f2f5","analyzedAt":"2026-08-15T12:14:11.722Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}