multica-ai/multica · warning

import source temporarily unavailable

Error message

import source temporarily unavailable

What it means

errImportSourceUnavailable marks a transient failure to read the upstream import source, classically the GitHub tree API rate limiting an unauthenticated or heavily-used client. The import cannot proceed safely now but should be retried later, so the handler maps it to a retryable HTTP status (5xx-class) rather than a permanent 400.

Source

Thrown at server/internal/handler/skill.go:630

	bundleSize  int            // running sum of file content bytes for cap enforcement
	origin      map[string]any // written into skill.config.origin so the UI can show provenance
}

type importedFile struct {
	path    string
	content string
}

// errImportCapExceeded marks an error caused by a per-file or per-bundle cap.
// Such errors must abort the import — silently dropping a file would otherwise
// produce an incomplete skill that looks valid to the user.
var errImportCapExceeded = errors.New("import cap exceeded")

// errImportSourceUnavailable marks a transient failure to read the upstream
// source (e.g. the GitHub tree API rate limiting). The import can't proceed
// safely but should be retried, so it maps to a retryable HTTP status rather
// than a permanent error.
var errImportSourceUnavailable = errors.New("import source temporarily unavailable")

// isCapError reports whether err is (or wraps) errImportCapExceeded.
func isCapError(err error) bool {
	return errors.Is(err, errImportCapExceeded)
}

// addFile appends a supporting file while enforcing the per-bundle caps. It
// returns an error when either the file count or aggregate byte budget would
// be exceeded so the caller fails the import instead of silently truncating.
//
// Binary files (images, fonts, archives) are silently skipped: their bytes
// can't survive a PG TEXT column (SQLSTATE 22021), and they're reference
// assets the agent never reads as text anyway. Logging the skip leaves a
// breadcrumb if a user expected one of these to import.
func (s *importedSkill) addFile(path, content string) error {
	if isLikelyBinaryFilePath(path) {
		slog.Info("skill import: skipping binary file", "path", path, "size", len(content))
		return nil

View on GitHub (pinned to 2c0912b6ec)

Solutions

  1. Retry with backoff after the rate-limit reset (honor x-ratelimit-reset when present)
  2. Configure a GitHub token for the importer so the rate ceiling rises dramatically
  3. Batch imports with delays instead of a tight loop

Example fix

// before
for (const repo of repos) await importSkill(repo); // burns the rate limit
// after
for (const repo of repos) {
  await importSkill(repo);
  await sleep(2000);
  // on 503/429-style retryable failure: exponential backoff and retry once or twice
}
Defensive patterns

Strategy: retry

Try / catch

async function importWithRetry(ref, attempts = 3) {
  for (let i = 0; i < attempts; i++) {
    try { return await importSkill(ref); }
    catch (e) {
      const retryable = e.status === 503 || e.status === 429 || /temporarily unavailable/i.test(e.message);
      if (!retryable || i === attempts - 1) throw e;
      await sleep(2 ** i * 1000);
    }
  }
}

Prevention

When it happens

Trigger: POST a GitHub skill import while the GitHub API is rate-limited (403 with x-ratelimit-remaining: 0), the tree API 5xx's, or the network drops mid-fetch. Repeating the identical request after the rate-limit window succeeds.

Common situations: Bulk-importing many skills in a loop from one IP; CI without a GITHUB_TOKEN; importing right after a burst of other GitHub API calls; transient upstream outages.

Related errors


AI-assisted analysis of multica-ai/multica@2c0912b6ec (2026-08-15). Data as JSON: /api/errors/4892e2af8b89fafd. Report an issue: GitHub.