{"record":{"id":"291e94364e60c2b3","repo":"temporalio/temporal","slug":"link-type-is-empty","errorCode":null,"errorMessage":"link type is empty","messagePattern":"link type is empty","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"common/nexus/nexusrpc/api.go","lineNumber":244,"sourceCode":"\t}\n\n\treturn link, nil\n}\n\nfunc validateLinkURL(value *url.URL) error {\n\tif value == nil || value.String() == \"\" {\n\t\treturn errors.New(\"url is empty\")\n\t}\n\t_, err := url.ParseQuery(value.RawQuery)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"url query not percent-encoded: %s\", value)\n\t}\n\treturn nil\n}\n\nfunc validateLinkType(value string) error {\n\tif len(value) == 0 {\n\t\treturn errors.New(\"link type is empty\")\n\t}\n\tfor _, c := range value {\n\t\tif (c < 'a' || c > 'z') && (c < 'A' || c > 'Z') && (c < '0' || c > '9') && c != '_' && c != '.' && c != '/' {\n\t\t\treturn errors.New(\"link type contains invalid char (valid chars: alphanumeric, '_', '.', '/')\")\n\t\t}\n\t}\n\treturn nil\n}\n\nvar durationRegexp = regexp.MustCompile(`^(\\d+(?:\\.\\d+)?)(ms|s|m)$`)\n\nfunc ParseDuration(value string) (time.Duration, error) {\n\tm := durationRegexp.FindStringSubmatch(value)\n\tif len(m) == 0 {\n\t\treturn 0, fmt.Errorf(\"invalid duration: %q\", value)\n\t}\n\tv, err := strconv.ParseFloat(m[1], 64)\n\tif err != nil {","sourceCodeStart":226,"sourceCodeEnd":262,"githubUrl":"https://github.com/temporalio/temporal/blob/bde624efd13fbd3843654058db6d9c716166318b/common/nexus/nexusrpc/api.go#L226-L262","documentation":"validateLinkType in common/nexus/nexusrpc/api.go checks that a Nexus link's type string is non-empty and composed only of alphanumeric characters, '_', '.', or '/'. When the type is an empty string the function rejects it with this error, since a link without a type is meaningless for routing/identification. It is returned by encodeLink and decodeLink when converting Nexus links to/from header representations.","triggerScenarios":"Calling encodeLink or decodeLink with a Link whose Type field is the empty string (e.g. a Link struct built manually without setting Type, or decoding a header where the type portion was omitted/blank).","commonSituations":"Manually constructing nexus links for callbacks in workflow code; an upstream producer writing link metadata headers without the type; trimming/parsing bugs that strip the type segment from a header value.","solutions":["Set a non-empty Type on the Link before encoding/decoding (e.g. the service or component name the link points to)","Verify the code producing the link metadata actually populates the type field","If parsing from headers, check the raw header value contains the type segment before calling decodeLink"],"exampleFix":"// before\nlink := &nexus.Link{URL: u, Type: \"\"}\n// after\nlink := &nexus.Link{URL: u, Type: \"temporal.api.failure.v1\"}","handlingStrategy":"validation","validationCode":"func validLinkType(t string) bool {\n    if t == \"\" { return false }\n    for _, c := range t {\n        if !((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_' || c == '.' || c == '/') { return false }\n    }\n    return true\n}\n// call validLinkType(link.Type) before encodeLink/decodeLink","typeGuard":"if link == nil || link.Type == \"\" { return fmt.Errorf(\"link type missing\") }","tryCatchPattern":"if err := nexusrpc.ValidateLinkType(link.Type); err != nil {\n    return fmt.Errorf(\"invalid nexus link type %q: %w\", link.Type, err)\n}","preventionTips":["Always initialize Link.Type from a known-good constant or service name","Mirror the allowed charset (alphanumerics, '_', '.', '/') in any UI/config that collects link types","Add unit tests covering empty and special-character link types"],"tags":["nexus","validation","input-validation"],"backgroundTag":"empty-required-field","analyzedSha":"bde624efd13fbd3843654058db6d9c716166318b","analyzedAt":"2026-09-01T07:18:39.080Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T05:18:18.240Z"}