{"record":{"id":"44d6f4875a5e0759","repo":"sipeed/picoclaw","slug":"api-base-is-required","errorCode":null,"errorMessage":"api base is required","messagePattern":"api base is required","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cmd/picoclaw/internal/model/online.go","lineNumber":26,"sourceCode":"\t\"strings\"\n\t\"time\"\n)\n\ntype modelEntry struct {\n\tID          string `json:\"id\"`\n\tName        string `json:\"name\"`\n\tDescription string `json:\"description\"`\n}\n\ntype modelsAPIResponse struct {\n\tData []modelEntry `json:\"data\"`\n}\n\n// fetchOpenAIModels GETs <baseURL>/models with Bearer auth and accepts both the\n// {data:[…]} envelope and a bare array shape used by various OpenAI-compatible servers.\nfunc fetchOpenAIModels(baseURL, apiKey string) ([]modelEntry, error) {\n\tif strings.TrimSpace(baseURL) == \"\" {\n\t\treturn nil, fmt.Errorf(\"api base is required\")\n\t}\n\tif strings.TrimSpace(apiKey) == \"\" {\n\t\treturn nil, fmt.Errorf(\"api key is required\")\n\t}\n\n\turl := strings.TrimRight(baseURL, \"/\") + \"/models\"\n\n\tclient := &http.Client{Timeout: 15 * time.Second}\n\treq, err := http.NewRequest(http.MethodGet, url, nil)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"build request: %w\", err)\n\t}\n\treq.Header.Set(\"Authorization\", \"Bearer \"+apiKey)\n\n\tresp, err := client.Do(req)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"request failed: %w\", err)\n\t}","sourceCodeStart":8,"sourceCodeEnd":44,"githubUrl":"https://github.com/sipeed/picoclaw/blob/49183d7e8daed0dba89ddbb6fcb60089401d9680/cmd/picoclaw/internal/model/online.go#L8-L44","documentation":"fetchOpenAIModels refuses to build a request when the api base is empty or only whitespace. In the CLI, --api-base (-b) is a required flag, so cobra already rejects a missing flag; this error is reached when the flag is present but blank (-b '' or -b '  ', trimmed to empty by runAdd) or when the add flow is invoked programmatically with no base while -m/--model is omitted (a model id skips the fetch entirely).","triggerScenarios":"picoclaw model add -b \"\" -k <key> with no -m; scripts injecting an unset/empty environment variable into -b; programmatic calls of runAdd with empty apiBase and empty modelID.","commonSituations":"Automation wrapping the command with a variable that is unset in that shell; users blanking the flag expecting a prompt; copy-paste from examples where the base placeholder was never replaced.","solutions":["Pass a real base: picoclaw model add -b https://api.openai.com/v1 -k <key>","Include the scheme (https:// or http://) and the documented prefix (often /v1)","If a script builds -b from a variable, assert the variable is non-empty before invoking picoclaw"],"exampleFix":"# before (OPENAI_BASE unset in this shell)\n$ picoclaw model add -b \"$OPENAI_BASE\" -k sk-...\nfetch models: api base is required\n\n# after\n$ OPENAI_BASE=https://api.openai.com/v1\n$ picoclaw model add -b \"$OPENAI_BASE\" -k sk-...","handlingStrategy":"validation","validationCode":"if strings.TrimSpace(apiBase) == \"\" {\n  return fmt.Errorf(\"--api-base is empty; pass a full URL like https://api.openai.com/v1\")\n}\nif _, err := url.ParseRequestURI(strings.TrimSpace(apiBase)); err != nil {\n  return fmt.Errorf(\"--api-base %q is not a valid URL\", apiBase)\n}","typeGuard":"func isAPIBaseRequiredError(err error) bool {\n  return err != nil && strings.Contains(err.Error(), \"api base is required\")\n}","tryCatchPattern":"if err := fetchOpenAIModels(apiBase, apiKey); err != nil {\n  if isAPIBaseRequiredError(err) {\n    // abort before network use; prompt for a non-empty base\n  }\n  return err\n}","preventionTips":["Assert ${VAR:+x} style checks before injecting variables into -b","Include scheme and host in every --api-base value","Prefer -m <model-id> when the base is uncertain — the fetch is skipped entirely"],"tags":["model","cli","validation","flags"],"backgroundTag":null,"analyzedSha":"49183d7e8daed0dba89ddbb6fcb60089401d9680","analyzedAt":"2026-08-15T21:55:41.315Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}