temporalio/temporal · error
name %s is invalid. name must follow golang identifier rules
Error message
name %s is invalid. name must follow golang identifier rules: %s
What it means
validateName rejects a component or task name that is empty or does not match nameValidator, a regex enforcing Go identifier rules (as reported via nameValidator.String()). Names become parts of FQNs and persisted identifiers, so they must be valid identifiers.
Source
Thrown at chasm/registry.go:339
if !(rt.componentGoType.Kind() == reflect.Interface ||
(rt.componentGoType.Kind() == reflect.Struct ||
(rt.componentGoType.Kind() == reflect.Pointer && rt.componentGoType.Elem().Kind() == reflect.Struct)) &&
rt.componentGoType.AssignableTo(reflect.TypeFor[Component]())) {
return fmt.Errorf("component type %s must be and interface or struct that implements Component interface", rt.componentGoType.String())
}
r.rtByFqn[fqn] = rt
r.rtByID[id] = rt
r.rtByGoType[rt.goType] = rt
return nil
}
func (r *Registry) validateName(n string) error {
if n == "" {
return errors.New("name must not be empty")
}
if !nameValidator.MatchString(n) {
return fmt.Errorf("name %s is invalid. name must follow golang identifier rules: %s", n, nameValidator.String())
}
return nil
}
func (r *Registry) validateVisibilityBusinessIDAlias(rc *RegistrableComponent) error {
if !hasVisibilityField(rc.goType) {
return nil
}
// Archetypes that contain a Field[*Visibility] must specify WithBusinessIDAlias.
if !rc.hasBusinessIDAlias() {
return fmt.Errorf("component %s has Field[*Visibility] but no businessID alias; use WithBusinessIDAlias option", rc.componentType)
}
return nil
}
func (r *Registry) warnUnmanagedFields(fqn string, rc *RegistrableComponent) {
var unmanagedFields []string
for f := range unmanagedFieldsOf(rc.goType) {View on GitHub (pinned to bde624efd1)
Solutions
- Rename to a valid Go identifier: letters/digits/underscores, not starting with a digit, e.g. "order_cleanup".
- Check the regex in the error message to see exactly which characters are allowed.
- If the name comes from config, sanitize/validate it before calling Register.
Example fix
// before chasm.RegisterTask[T, C](reg, "order-cleanup", opts) // after chasm.RegisterTask[T, C](reg, "order_cleanup", opts)
Defensive patterns
Strategy: validation
Validate before calling
var nameValidator = regexp.MustCompile(`^[a-zA-Z_][a-zA-Z0-9_]*$`)
if !nameValidator.MatchString(name) {
return fmt.Errorf("name %q must be a valid Go identifier", name)
} Prevention
- Use snake_case Go identifiers for component/task names — no hyphens or dots.
- Validate any config/env-derived names before passing them to Register.
- Never pass an empty name; require callers to supply a non-empty constant.
When it happens
Trigger: Registering a component/task whose registered name contains hyphens, spaces, dots, leading digits, or other non-identifier characters; passing an empty name string.
Common situations: Using a kebab-case or dotted service name like "order-cleanup" or "orders.v1" as the task type; building names dynamically from config or env values with unexpected formatting; forgetting the name argument entirely (empty string).
Related errors
- ErrDuplicateRegistration
- errInvalidWorkflowExecutionTimeoutSeconds
- errInvalidWorkflowRunTimeoutSeconds
- errInvalidWorkflowTaskTimeoutSeconds
- component type %s must be struct or pointer to struct
AI-assisted analysis of temporalio/temporal@bde624efd1 (2026-09-01).
Data as JSON: /api/errors/603f9f04384ad241.
Report an issue: GitHub.