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

  1. Set a non-empty run ID (client normally generates a UUID/metainfo-based ID automatically)
  2. If writing a custom client, populate msg.Login.RunID before dialing frps
  3. 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

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


AI-assisted analysis of fatedier/frp@6c8a8d0a97 (2026-08-15). Data as JSON: /api/errors/93af073f918a731f. Report an issue: GitHub.