fatedier/frp · error
%s cannot be empty
Error message
%s cannot be empty
What it means
Generic identifier validator (used e.g. by ValidateRunID for the control run ID, max 64 bytes): the value is the empty string. frp requires these identifiers to be non-empty because they key sessions, routing and bookkeeping on the server.
Source
Thrown at pkg/config/v1/validation/name.go:30
// See the License for the specific language governing permissions and
// limitations under the License.
package validation
import (
"fmt"
"unicode"
"unicode/utf8"
)
const (
// MaxRunIDLength is the maximum number of bytes accepted for a control run ID.
MaxRunIDLength = 64
)
func validateIdentifier(value, kind string, maxLength int) error {
if value == "" {
return fmt.Errorf("%s cannot be empty", kind)
}
if len(value) > maxLength {
return fmt.Errorf("%s is too long: length %d exceeds maximum %d", kind, len(value), maxLength)
}
if !utf8.ValidString(value) {
return fmt.Errorf("%s must be valid UTF-8", kind)
}
for _, r := range value {
if !unicode.IsPrint(r) {
return fmt.Errorf("%s contains non-printable character", kind)
}
}
return nil
}
func ValidateRunID(runID string) error {
return validateIdentifier(runID, "run id", MaxRunIDLength)
}View on GitHub (pinned to 6c8a8d0a97)
Solutions
- Set a non-empty run ID (client normally generates a UUID/metainfo-based ID automatically)
- If writing a custom client, populate msg.Login.RunID before dialing frps
- If you see this as an frps operator, it usually indicates a broken/old client — update frpc
Example fix
// before
login := &msg.Login{
User: "",
RunID: "",
}
// after
login := &msg.Login{
User: "",
RunID: uuid.NewString(),
} Defensive patterns
Strategy: validation
Validate before calling
if err := validation.ValidateRunID(runID); err != nil {
// reject/repair before sending msg.Login
} Type guard
func isValidRunID(s string) bool {
return s != ""
} Try / catch
if err := validation.ValidateRunID(id); err != nil {
if strings.Contains(err.Error(), "cannot be empty") {
id = uuid.NewString() // regenerate and retry once
}
} Prevention
- Always generate a run ID (UUID) in custom clients at connect time
- Never pass through empty identifiers from upstream data
When it happens
Trigger: ValidateRunID("") — the server receives a login/register message whose RunID field is empty (malformed client, protocol misuse, or a custom client built against msg.Login). Other call sites pass their own kind label.
Common situations: Custom clients or tests constructing frp control messages without setting RunID; protocol-level bugs where the field is dropped during serialization; fuzzing the control connection.
Related errors
- %s is too long: length %d exceeds maximum %d
- %s must be valid UTF-8
- invalid transport.protocol, optional values are %v
- unexpected message type %s, want %s
- get natHoleRespMsg error: invalid message type
AI-assisted analysis of fatedier/frp@6c8a8d0a97 (2026-08-15).
Data as JSON: /api/errors/93af073f918a731f.
Report an issue: GitHub.