Tencent/WeKnora · error

invalid task ID format: %s

Error message

invalid task ID format: %s

What it means

ParseTaskID splits a task ID on '_' and requires at least 4 segments: task type parts, tenant ID, timestamp, and UUID. If fewer than 4 underscore-separated parts exist the ID cannot contain the mandatory tenant_timestamp pair and 'invalid task ID format' is returned. Task types may themselves contain underscores, so the parser scans for the tenant/timestamp pair rather than trusting the first segment.

Source

Thrown at internal/utils/taskid.go:73

	}

	if len(businessID) > 0 && businessID[0] != "" {
		components = append(components, sanitizeBusinessID(businessID[0]))
	}

	return strings.Join(components, "_")
}

// ParseTaskID parses a task ID generated by GenerateTaskID and returns its components.
// Returns taskType, tenantID, timestamp, uuid, businessID, and error.
//
// Task types may contain underscores (e.g. "faq_import", "kb_clone"), so the
// parser locates the tenant/timestamp pair rather than assuming parts[0] is
// the full task type.
func ParseTaskID(taskID string) (taskType string, tenantID uint64, timestamp int64, uuidPart string, businessID string, err error) {
	parts := strings.Split(taskID, "_")
	if len(parts) < 4 {
		err = fmt.Errorf("invalid task ID format: %s", taskID)
		return
	}

	tenantIdx := -1
	for i := 1; i < len(parts)-2; i++ {
		candidateTenant, parseErr := strconv.ParseUint(parts[i], 10, 64)
		if parseErr != nil || candidateTenant == 0 {
			continue
		}
		candidateTS, parseErr := strconv.ParseInt(parts[i+1], 10, 64)
		if parseErr != nil || candidateTS < 1_000_000_000_000 {
			continue
		}
		tenantID = candidateTenant
		timestamp = candidateTS
		tenantIdx = i
		break
	}

View on GitHub (pinned to 988cbb0330)

Solutions

  1. Regenerate the task ID with the correct format: <taskType>_<tenantID>_<timestamp>_<uuid> (e.g. faq_import_42_1700000000_ab12cd34)
  2. Log the full raw taskID value and count its '_' segments to confirm the corruption point
  3. Check the producer that created the ID for missing tenant/timestamp/uuid fields
  4. Add validation at the producer side so malformed IDs are never enqueued

Example fix

// before
taskID := "kb_clone_42" // only 3 segments
// after
taskID := "kb_clone_42_1700000000_9f8e7d6c" // taskType_tenant_ts_uuid
Defensive patterns

Strategy: validation

Validate before calling

parts := strings.Split(taskID, "_")
if len(parts) < 4 {
    return fmt.Errorf("task ID %q too short: need <type>_<tenant>_<ts>_<uuid>", taskID)
}

Type guard

func looksLikeTaskID(id string) bool {
    parts := strings.Split(id, "_")
    if len(parts) < 4 { return false }
    for i := 1; i < len(parts)-2; i++ {
        tenant, e1 := strconv.ParseUint(parts[i], 10, 64)
        _, e2 := strconv.ParseInt(parts[i+1], 10, 64)
        if e1 == nil && e2 == nil && tenant > 0 { return true }
    }
    return false
}

Try / catch

taskType, tenantID, ts, uuid, biz, err := utils.ParseTaskID(raw)
if err != nil {
    log.Printf("unparseable task ID %q: %v", raw, err)
    return fmt.Errorf("corrupt task ID from queue: %w", err)
}

Prevention

When it happens

Trigger: ParseTaskID (via TaskTenantID or tests) receives a task ID with fewer than 4 '_'-separated segments — e.g. 'import_123', 'faqs', an empty string, or a truncated/corrupted ID read from a queue message or DB row.

Common situations: Legacy task IDs generated by an older ID format, IDs truncated by column limits or log copy-paste, hand-written test fixtures, or a producer bug that skipped appending tenant/timestamp/uuid segments.

Related errors


AI-assisted analysis of Tencent/WeKnora@988cbb0330 (2026-09-02). Data as JSON: /api/errors/d571ee07e3a2f3cc. Report an issue: GitHub.